#ifdef KITSCHY_DEBUG_MEMORY 
#include "debug_memorymanager.h"
#endif

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdarg.h"
#include "assert.h"

#include "BList.h"

#include "symbol.h"
#include "sort.h"
#include "ontology.h"
#include "featureterm.h"
#include "FTKBase.h"

#include "SpecialTerm.h"


FeatureTerm::FeatureTerm(Symbol *name,int i,Ontology *o)
{
	m_ft=new FeatureTermContainer(name,i,0,o);
} /* FeatureTerm::FeatureTerm */ 


FeatureTerm::FeatureTerm(Symbol *name,float f,Ontology *o)
{
	m_ft=new FeatureTermContainer(name,f,0,o);
} /* FeatureTerm::FeatureTerm */ 


FeatureTerm::FeatureTerm(Symbol *name,Symbol *s,Ontology *o)
{
	m_ft=new FeatureTermContainer(name,s,o);
} /* FeatureTerm::FeatureTerm */ 


FeatureTerm::FeatureTerm(Symbol *name,Sort *sort,int nfeatures,...)
{
	va_list	ap;
	va_start(ap, nfeatures);

	m_ft=new FeatureTermContainer(name,sort,nfeatures,ap);
	
	va_end(ap);	
	
	{
		List<Symbol> *fl=sort->getFeatures();
		Symbol *f;
		FeatureTerm *dv;

		fl->Rewind();
		while(fl->Iterate(f)) {
			if (featureValueQuick(f)==0) {
				dv=sort->featureDefaultValue(f);
				if (dv!=0) defineFeatureValue(f,new FeatureTerm(dv));
			} // if 
		} // while 
		delete fl;
	}

} /* FeatureTerm::FeatureTerm */ 


FeatureTerm::FeatureTerm(Symbol *name,SpecialTerm *st,Sort *sort)
{	
	m_ft=new FeatureTermContainer(name,st,sort);
} /* FeatureTerm::FeatureTerm */ 


FeatureTerm::FeatureTerm(FeatureTerm &f)
{
	m_ft=f.m_ft;
	if (m_ft!=0) m_ft->m_reference_count++;
} /* FeatureTerm::FeatureTerm */ 


FeatureTerm::FeatureTerm(FeatureTerm *f)
{
	m_ft=f->m_ft;
	if (m_ft!=0) m_ft->m_reference_count++;
} /* FeatureTerm::FeatureTerm */ 


FeatureTerm::FeatureTerm(FeatureTermContainer *fv)
{
	assert(fv!=0);
	m_ft=fv;
	if (m_ft!=0) m_ft->m_reference_count++;
} /* FeatureTerm::FeatureTerm */ 


FeatureTerm::FeatureTerm(void)
{
	m_ft=0;
} /* FeatureTerm::FeatureTerm */ 



FeatureTerm::FeatureTerm(char *name,int i,Ontology *o)
{
	if (name!=0) m_ft=new FeatureTermContainer(new Symbol(name),i,0,o);
			else m_ft=new FeatureTermContainer((Symbol *)0,i,0,o);
} /* FeatureTerm::FeatureTerm */ 


FeatureTerm::FeatureTerm(char *name,float f,Ontology *o)
{
	if (name!=0) m_ft=new FeatureTermContainer(new Symbol(name),f,0,o);
		    else m_ft=new FeatureTermContainer((Symbol *)0,f,0,o);
} /* FeatureTerm::FeatureTerm */ 


FeatureTerm::FeatureTerm(char *name,char *s,Ontology *o)
{
	if (name!=0) m_ft=new FeatureTermContainer(new Symbol(name),new Symbol(s),o);
			else m_ft=new FeatureTermContainer((Symbol *)0,new Symbol(s),o);
} /* FeatureTerm::FeatureTerm */ 


FeatureTerm::FeatureTerm(char *name,Sort *sort,int nfeatures,...)
{
	va_list	ap;
	va_start(ap, nfeatures);

	m_ft=new FeatureTermContainer(name,sort,nfeatures,ap);
	
	va_end(ap);	

	{
		List<Symbol> *fl=sort->getFeatures();
		Symbol *f;
		FeatureTerm *dv;

		fl->Rewind();
		while(fl->Iterate(f)) {
			if (featureValueQuick(f)==0) {
				dv=sort->featureDefaultValue(f);
				if (dv!=0) defineFeatureValue(f,new FeatureTerm(dv));
			} // if 
		} // while 
		delete fl;
	}
} /* FeatureTerm::FeatureTerm */ 


FeatureTerm::FeatureTerm(char *name,SpecialTerm *st,char *sort,Ontology *o)
{	
	if (name!=0) m_ft=new FeatureTermContainer(new Symbol(name),st,o->get_sort(sort));
			else m_ft=new FeatureTermContainer((Symbol *)0,st,o->get_sort(sort));
} /* FeatureTerm::FeatureTerm */ 



FeatureTerm *FeatureTerm::SetFeatureTerm(void)
{
	FeatureTerm *f=new FeatureTerm();
	f->m_ft=new FeatureTermContainer(0);

	return f;
} /* FeatureTerm::FeatureTermSetFeatureTerm */ 


FeatureTerm *FeatureTerm::SetFeatureTerm(Symbol *name)
{
	FeatureTerm *f=new FeatureTerm();
	f->m_ft=new FeatureTermContainer(name);
	return f;
} /* FeatureTerm::SetFeatureTerm */ 


FeatureTerm *FeatureTerm::SetFeatureTerm(char *name)
{
	FeatureTerm *f=new FeatureTerm();
	if (name!=0) f->m_ft=new FeatureTermContainer(new Symbol(name));
		    else f->m_ft=new FeatureTermContainer((Symbol *)0);
	return f;
} /* FeatureTerm::SetFeatureTerm */ 



FeatureTerm::~FeatureTerm()
{
	Delete();
} /* FeatureTerm::~FeatureTerm */ 


void FeatureTerm::Delete(void)
{
//	printf("D\n");
	if (m_ft!=0) {
		m_ft->m_reference_count--;
		if (m_ft->m_reference_count<=0) {
//			printf("*--------* -> %s \n",(m_ft->m_name==0 ? "???":m_ft->m_name->get()));
			delete m_ft;
		} else {
			/* Check for circularities in the structure to properly free all the allocated memory: */ 
			List<FeatureTermContainer> l1,l1a,todelete;
			List<FeatureTerm> expanded,delayed,*tmp;
			List<List<FeatureTerm> > l2,l2a;
			FeatureTermContainer *ftv;
			FeatureTerm *ft;

			m_ft->num_of_references(this,&l1,&l2);

			/* Visualize the reference table: */ 
/*
			printf("/--------\\ -> %s \n",(m_ft->m_name==0 ? "???":m_ft->m_name->get()));
			l1.Rewind();
			l2.Rewind();
			while(l1.Iterate(ftv) &&
				  l2.Iterate(tmp)) {
				printf("%p %s %i (found %i)\n",ftv,(ftv->m_name==0 ? "???":ftv->m_name->get()),ftv->m_reference_count,tmp->Length());
			} // while  
			printf("+--------+\n");
*/
			/* find accesible nodes from the non-deletable nodes: */ 
			l1.Rewind();
			l2.Rewind();
			while(l1.Iterate(ftv) &&
				  l2.Iterate(tmp)) {
				int n=tmp->Length();
				if (ftv==m_ft) n--;
				if (ftv->m_reference_count>n) ftv->num_of_references(tmp->operator [](0),&l1a,&l2a);
			} /* while */ 

			/* find nodes to delete: */ 
			l1.Rewind();
			while(l1.Iterate(ftv)) {
				if (!l1a.MemberRefP(ftv)) {
//					printf("To delete: %p %s %i\n",ftv,(ftv->m_name==0 ? "???":ftv->m_name->get()),ftv->m_reference_count);
					todelete.Add(ftv);
				} /* if */ 
			} /* while */ 

//			printf("\\--------/\n");

			/* delete those nodes: */ 
//			if (todelete.MemberRefP(m_ft)) m_ft->m_reference_count++;
			m_ft->m_reference_count++;
			delete_circular_structure(&todelete,&expanded,&delayed);

			while(!todelete.EmptyP()) todelete.ExtractIni();
			while(!expanded.EmptyP()) expanded.ExtractIni();
			while(!delayed.EmptyP()) {
				ft=delayed.ExtractIni();
				if (ft!=this) {
					ft->m_ft=0;
					delete ft;
				} /* if */ 
			} /* while */ 

			while(!l1.EmptyP()) l1.ExtractIni();
			while(!l1a.EmptyP()) l1a.ExtractIni();
			while(!l2a.EmptyP()) {
				tmp=l2a.ExtractIni();
				while(!tmp->EmptyP()) tmp->ExtractIni();
				delete tmp;
			} /* ewhile */ 
			while(!l2.EmptyP()) {
				tmp=l2.ExtractIni();
				while(!tmp->EmptyP()) tmp->ExtractIni();
				delete tmp;
			} /* ewhile */ 
		} /* if */ 
		m_ft=0;
	} /* if */ 
} /* FeatureTerm::Delete */ 


void FeatureTerm::assign(FeatureTerm *f)
{
	Delete();
	m_ft=f->m_ft;
	f->m_ft->m_reference_count++;
} /* FeatureTerm::assign */ 


FeatureTerm *FeatureTerm::featureValue(Symbol *feature)
{
	if (m_ft==0) return 0;
	if (m_ft->m_data_type==DATATYPE_FEATURETERM) {
		List<FeatureTerm> l;
		FeatureTerm *f;
		List<Symbol> l2;
		Symbol *s;

		assert(m_ft->m_value.m_ft.m_feature_name->Length()==
			   m_ft->m_value.m_ft.m_feature_value->Length());

		l.Instance(*(m_ft->m_value.m_ft.m_feature_value));
		l2.Instance(*(m_ft->m_value.m_ft.m_feature_name));
		l.Rewind();
		l2.Rewind();
		while(l.Iterate(f) && l2.Iterate(s)) {
			if (*s==*feature) return new FeatureTerm(f);
		} /* while */ 

		return 0;
	} /* if */ 
	if (m_ft->m_data_type==DATATYPE_SET) {
		FeatureTerm *result=FeatureTerm::SetFeatureTerm();
		List<FeatureTerm> l;
		FeatureTerm *f,*f2;

		l.Instance(*m_ft->m_value.m_set);
		l.Rewind();
		while(l.Iterate(f)) {
			f2=f->featureValue(feature);
			if (f2!=0) result->addSetValue(f2);
		} /* while */ 

		if (result->m_ft->m_value.m_set->EmptyP()) {
			delete result;
			result=0;
		} /* if */ 

		return result;
	} /* if */ 
	if (m_ft->m_data_type==DATATYPE_SPECIAL) {
		return m_ft->m_value.m_special->featureValue(feature);
	} // if

	return 0;
} /* FeatureTerm::featureValue */ 



FeatureTerm *FeatureTerm::featureValueQuick(char *feature)
{
	FeatureTerm *tmp;
	Symbol *s=new Symbol(feature);

	tmp=featureValueQuick(s);
	delete s;

	return tmp;
} /* FeatureTerm::featureValueQuick */ 



FeatureTerm *FeatureTerm::featureValueQuick(Symbol *feature)
{
	if (m_ft==0) return 0;
	if (m_ft->m_data_type==DATATYPE_FEATURETERM) {
		List<FeatureTerm> l;
		FeatureTerm *f;
		List<Symbol> l2;
		Symbol *s;

		assert(m_ft->m_value.m_ft.m_feature_name->Length()==
			   m_ft->m_value.m_ft.m_feature_value->Length());

		l.Instance(*(m_ft->m_value.m_ft.m_feature_value));
		l2.Instance(*(m_ft->m_value.m_ft.m_feature_name));
		l.Rewind();
		l2.Rewind();
		while(l.Iterate(f) && l2.Iterate(s)) {
			if (*s==*feature) return f;
		} /* while */ 

		return 0;
	} /* if */ 
	if (m_ft->m_data_type==DATATYPE_SPECIAL) {
		return m_ft->m_value.m_special->featureValueQuick(feature);
	} // if
	return 0;
} /* FeatureTerm::featureValueQuick */ 


void FeatureTerm::defineFeatureValue(Symbol *feature,FeatureTerm *value)
{
	if (m_ft==0 || m_ft->m_data_type!=DATATYPE_FEATURETERM) {
		printf("Warning: defineFeatureValue (Symbol)!!!\n");
		return;
	} /* if */ 

	assert(m_ft->m_value.m_ft.m_feature_name->Length()==
		   m_ft->m_value.m_ft.m_feature_value->Length());

	int pos=m_ft->m_value.m_ft.m_feature_name->Position(feature);

	if (pos==-1) {
		m_ft->m_value.m_ft.m_feature_name->Add(new Symbol(feature));
		m_ft->m_value.m_ft.m_feature_value->Add(value);
	} else {
		m_ft->m_value.m_ft.m_feature_value->GoTo(pos);

		delete m_ft->m_value.m_ft.m_feature_value->GetObj();
		m_ft->m_value.m_ft.m_feature_value->SetObj(value);
	} /* if */ 

} /* FeatureTerm::defineFeatureValue */ 


// checks the SORT to see if the feature exists  
// and if the value has the correct sort
bool FeatureTerm::defineFeatureValueSecure(Symbol *feature,FeatureTerm *value)
{
	bool singleton=false;

	if (m_ft==0 || m_ft->m_data_type!=DATATYPE_FEATURETERM) {
		printf("defineFeatureValueSecure: error 1\n");
		return false;
	} // if 

	if (!m_ft->m_sort->hasFeature(feature)) {
		printf("defineFeatureValueSecure: error 2\n");
		return false;
	} // if 
	if (!m_ft->m_sort->featureSort(feature)->inSort(value)) {
		printf("defineFeatureValueSecure: error 3\n");
		return false;
	} // if 
	
	assert(m_ft->m_value.m_ft.m_feature_name->Length()==
		   m_ft->m_value.m_ft.m_feature_value->Length());

	int pos=m_ft->m_value.m_ft.m_feature_name->Position(feature);
	singleton=m_ft->m_sort->featureSingleton(feature);

	if (singleton && value->isSet()) {
		printf("defineFeatureValueSecure: error 4\n");
		return false;
	} // if 

	if (pos==-1) {
		m_ft->m_value.m_ft.m_feature_name->Add(new Symbol(feature));
		m_ft->m_value.m_ft.m_feature_value->Add(value);
	} else {
		m_ft->m_value.m_ft.m_feature_value->GoTo(pos);

		delete m_ft->m_value.m_ft.m_feature_value->GetObj();
		m_ft->m_value.m_ft.m_feature_value->SetObj(value);
	} /* if */ 

	return true;
} /* FeatureTerm::defineFeatureValueSecure */ 



FeatureTerm *FeatureTerm::featureValue(char *feature)
{
	if (m_ft==0) return 0;
	if (m_ft->m_data_type==DATATYPE_FEATURETERM) {
		List<FeatureTerm> l;
		FeatureTerm *f;
		List<Symbol> l2;
		Symbol *s;

		assert(m_ft->m_value.m_ft.m_feature_name->Length()==
			   m_ft->m_value.m_ft.m_feature_value->Length());

		l.Instance(*(m_ft->m_value.m_ft.m_feature_value));
		l2.Instance(*(m_ft->m_value.m_ft.m_feature_name));
		l.Rewind();
		l2.Rewind();
		while(l.Iterate(f) && l2.Iterate(s)) {
			if (s->cmp(feature)) return new FeatureTerm(f);
		} /* while */ 

		return 0;
	} /* if */ 
	if (m_ft->m_data_type==DATATYPE_SET) {
		FeatureTerm *result=FeatureTerm::SetFeatureTerm();
		List<FeatureTerm> l;
		FeatureTerm *f,*f2;

		l.Instance(*m_ft->m_value.m_set);
		l.Rewind();
		while(l.Iterate(f)) {
			f2=f->featureValue(feature);
			if (f2!=0) result->addSetValue(f2);
		} /* while */ 

		if (result->m_ft->m_value.m_set->EmptyP()) {
			delete result;
			result=0;
		} /* if */ 

		return result;
	} /* if */ 
	return 0;
} /* FeatureTerm::featureValue */ 


void FeatureTerm::defineFeatureValue(char *feature,FeatureTerm *value)
{
	if (m_ft==0 || m_ft->m_data_type!=3) {
		printf("Warning: defineFeatureValue (char)!!!\n");
		return;
	} /* if */ 

	assert(m_ft->m_value.m_ft.m_feature_name->Length()==
		   m_ft->m_value.m_ft.m_feature_value->Length());

	Symbol *f=new Symbol(feature);
	int pos=m_ft->m_value.m_ft.m_feature_name->Position(f);
	delete f;

	if (pos==-1) {
		m_ft->m_value.m_ft.m_feature_name->Add(new Symbol(feature));
		m_ft->m_value.m_ft.m_feature_value->Add(value);
	} else {
		m_ft->m_value.m_ft.m_feature_value->GoTo(pos);

		delete m_ft->m_value.m_ft.m_feature_value->GetObj();
		m_ft->m_value.m_ft.m_feature_value->SetObj(value);
	} /* if */ 

} /* FeatureTerm::defineFeatureValue */ 


// checks the SORT to see if the feature exists  
// and if the value has the correct sort
bool FeatureTerm::defineFeatureValueSecure(char *feature,FeatureTerm *value)
{
	bool singleton=false;

	if (m_ft==0 || m_ft->m_data_type!=DATATYPE_FEATURETERM) {
		printf("defineFeatureValueSecure: error 1\n");
		return false;
	} // if 

	if (!m_ft->m_sort->hasFeature(feature)) {
		printf("defineFeatureValueSecure: error 2\n");
		return false;
	} // if 
	if (!m_ft->m_sort->featureSort(feature)->inSort(value)) {
		printf("defineFeatureValueSecure: error 3\n");
		return false;
	} // if 
	
	assert(m_ft->m_value.m_ft.m_feature_name->Length()==
		   m_ft->m_value.m_ft.m_feature_value->Length());

	Symbol *f=new Symbol(feature);
	int pos=m_ft->m_value.m_ft.m_feature_name->Position(f);
	delete f;

	singleton=m_ft->m_sort->featureSingleton(feature);

	if (singleton && value->isSet()) {
		printf("defineFeatureValueSecure: error 4\n");
		return false;
	} // if 

	if (pos==-1) {
		m_ft->m_value.m_ft.m_feature_name->Add(new Symbol(feature));
		m_ft->m_value.m_ft.m_feature_value->Add(value);
	} else {
		m_ft->m_value.m_ft.m_feature_value->GoTo(pos);

		delete m_ft->m_value.m_ft.m_feature_value->GetObj();
		m_ft->m_value.m_ft.m_feature_value->SetObj(value);
	} /* if */ 

	return true;
} /* FeatureTerm::defineFeatureValueSecure */ 


void FeatureTerm::removeFeatureValue(char *feature)
{
	if (m_ft==0) return;
	if (m_ft->m_data_type==DATATYPE_FEATURETERM) {
		Symbol *s=new Symbol(feature);
		Symbol *s2;
		FeatureTerm *f;
		int pos;

		assert(m_ft->m_value.m_ft.m_feature_name->Length()==
			   m_ft->m_value.m_ft.m_feature_value->Length());

		pos=m_ft->m_value.m_ft.m_feature_name->Position(s);
		if (pos!=-1) {
			s2=m_ft->m_value.m_ft.m_feature_name->operator [](pos);
			f=m_ft->m_value.m_ft.m_feature_value->operator [](pos);
			m_ft->m_value.m_ft.m_feature_name->DeletePosition(pos);
			m_ft->m_value.m_ft.m_feature_value->DeletePosition(pos);
			delete s2;
			delete f;
		} /* if */ 
		delete s;
	} /* if */ 
	if (m_ft->m_data_type==DATATYPE_SET) {
		List<FeatureTerm> l;
		FeatureTerm *f;

		l.Instance(*m_ft->m_value.m_set);
		l.Rewind();
		while(l.Iterate(f)) {
			f->removeFeatureValue(feature);
		} /* while */ 
	} /* if */ 
} /* FeatureTerm::removeFeatureValue */ 


void FeatureTerm::removeFeatureValue(Symbol *feature)
{
	if (m_ft==0) return;
	if (m_ft->m_data_type==DATATYPE_FEATURETERM) {
		Symbol *s2;
		FeatureTerm *f;
		int pos;

		assert(m_ft->m_value.m_ft.m_feature_name->Length()==
			   m_ft->m_value.m_ft.m_feature_value->Length());

		pos=m_ft->m_value.m_ft.m_feature_name->Position(feature);
		if (pos!=-1) {
			s2=m_ft->m_value.m_ft.m_feature_name->operator [](pos);
			f=m_ft->m_value.m_ft.m_feature_value->operator [](pos);
			m_ft->m_value.m_ft.m_feature_name->DeletePosition(pos);
			m_ft->m_value.m_ft.m_feature_value->DeletePosition(pos);
			delete s2;
			delete f;
		} /* if */ 
	} /* if */ 
	if (m_ft->m_data_type==DATATYPE_SET) {
		List<FeatureTerm> l;
		FeatureTerm *f;

		l.Instance(*m_ft->m_value.m_set);
		l.Rewind();
		while(l.Iterate(f)) {
			f->removeFeatureValue(feature);
		} /* while */ 
	} /* if */ 
} /* FeatureTerm::removeFeatureValue */ 


void FeatureTerm::removeSetValue(FeatureTerm *value)
{
	int pos;

	if (m_ft==0 || m_ft->m_data_type!=4) return;

	pos=m_ft->m_value.m_set->Position(value);

	if (pos!=-1) {
		value=m_ft->m_value.m_set->operator [](pos);
		m_ft->m_value.m_set->DeletePosition(pos);
		delete value;
	} /* if */ 
} /* FeatureTerm::removeSetValue */ 





FeatureTerm *FeatureTerm::addSetValue(FeatureTerm *value)
{
	if (m_ft==0 || m_ft->m_data_type!=4) return 0;

	m_ft->m_value.m_set->Add(value);
	return value;
} /* FeatureTerm::addSetValue */ 


FeatureTermContainer* FeatureTerm::get_content(void)
{
	return m_ft;
} /* FeatureTerm::get_content */ 


Sort *FeatureTerm::getSort(void)
{
	Sort *s=0,*s2=0;

	if (m_ft==0) return 0;
	if (m_ft->m_sort!=0) return m_ft->m_sort;
	if (m_ft->m_data_type!=4) return 0;

	/* Find the most specific sort that subsumes all the set items: */ 
	{
		List<FeatureTerm> l;
		FeatureTerm *f;

		l.Instance(*(m_ft->m_value.m_set));
		l.Rewind();
		while(l.Iterate(f)) {
			s2=f->getSort();
			if (s2==0) return 0;
			if (s==0) {
				s=s2;
			} else {
				s=s->Antiunification(s2);
			} /* if */ 
		} /* while */ 

		return s;
	}
} /* FeatureTerm::getSort */ 


void FeatureTerm::setSort(Sort *s)
{
	if (m_ft==0) return;
	m_ft->m_sort=s;
	if (m_ft->m_data_type!=s->get_data_type()) {
		switch(m_ft->m_data_type) {
		case DATATYPE_SYMBOL: delete m_ft->m_value.m_s;
							  break;
		case DATATYPE_FEATURETERM: delete m_ft->m_value.m_ft.m_feature_name;
								   delete m_ft->m_value.m_ft.m_feature_value;
								   break;
		case DATATYPE_SET: delete m_ft->m_value.m_set;
						   break;
		case DATATYPE_SPECIAL:
							delete m_ft->m_value.m_special;
							break;
		} /* switch */ 

		m_ft->m_data_type=s->get_data_type();
		switch(m_ft->m_data_type) {
		case DATATYPE_INTEGER: 
				m_ft->m_value.m_i.m_value=0;
				m_ft->m_value.m_i.m_type=-1;
				break;
		case DATATYPE_FLOAT: 
				m_ft->m_value.m_f.m_value=0;
				m_ft->m_value.m_f.m_type=-1;
				break;
		case DATATYPE_SYMBOL: 
				m_ft->m_value.m_s=0;
				break;
		case DATATYPE_FEATURETERM:
				m_ft->m_value.m_ft.m_feature_name=new List<Symbol>;
				m_ft->m_value.m_ft.m_feature_value=new List<FeatureTerm>;
				break;
		case DATATYPE_SPECIAL:
				m_ft->m_value.m_special=s->createSpecial(0,0);
				break;
		} /* switch */ 
	} /* if */ 
} /* FeatureTerm::setSort */ 


Symbol *FeatureTerm::getName(void)
{
	if (m_ft!=0) return m_ft->m_name;
	return 0;
} /* FeatureTerm::getName */ 


void FeatureTerm::setName(Symbol *name)
{
	if (m_ft!=0) {
		if (m_ft->m_name!=0) delete m_ft->m_name;
		m_ft->m_name=name;
	} // if 
} /* FeatureTerm::setName */ 


int FeatureTerm::getDataType(void)
{
	if (m_ft!=0) return m_ft->m_data_type;
	return DATATYPE_ABSTRACT;
} /* FeatureTerm::getDataType */ 



int FeatureTerm::getInt(void)
{
	if (m_ft==0 ||
		m_ft->m_data_type!=DATATYPE_INTEGER) return 0;

	return m_ft->m_value.m_i.m_value;
} /* FeatureTerm::getInt */ 


bool FeatureTerm::specificIntValueP(void)
{
	if (m_ft==0 ||
		m_ft->m_data_type!=DATATYPE_INTEGER) return 0;

	if (m_ft->m_value.m_i.m_type==0) return true;
	return false;
} /* FeatureTerm::specificIntValueP */ 



bool FeatureTerm::specificFloatValueP(void)
{
	if (m_ft==0 ||
		m_ft->m_data_type!=DATATYPE_FLOAT) return 0;

	if (m_ft->m_value.m_f.m_type==0) return true;
	return false;
} /* FeatureTerm::specificFloatValueP */ 


float FeatureTerm::getFloat(void)
{
	if (m_ft==0 ||
		m_ft->m_data_type!=DATATYPE_FLOAT) return 0;

	return m_ft->m_value.m_f.m_value;
} /* FeatureTerm::getFloat */ 


Symbol *FeatureTerm::getSymbol(void)
{
	if (m_ft==0 ||
		m_ft->m_data_type!=DATATYPE_SYMBOL) return 0;

	return m_ft->m_value.m_s;
} /* FeatureTerm::getSymbol */ 


SpecialTerm *FeatureTerm::getSpecialTerm(void)
{
	if (m_ft==0 ||
		m_ft->m_data_type!=DATATYPE_SPECIAL) return 0;
	return m_ft->m_value.m_special;
} /* FeatureTerm::getSpecialTerm */ 


bool FeatureTerm::hasValue(void)
{
	if (m_ft==0) return false;
	if (m_ft->m_data_type==DATATYPE_INTEGER) {
		return m_ft->m_value.m_i.m_type!=-1;
	} /* if */ 
	if (m_ft->m_data_type==DATATYPE_FLOAT) {
		return m_ft->m_value.m_f.m_type!=-1;
	} /* if */ 
	if (m_ft->m_data_type==DATATYPE_SYMBOL) {
		return m_ft->m_value.m_s!=0;
	} /* if */ 
	if (m_ft->m_data_type==DATATYPE_FEATURETERM) {
		return !leafP();
	} /* if */ 
	if (m_ft->m_data_type==DATATYPE_SET) {
		return !(m_ft->m_value.m_set->EmptyP());
	} /* if */ 
	if (m_ft->m_data_type==DATATYPE_SPECIAL) {
		return m_ft->m_value.m_special!=0;
	} /* if */ 
	return false;
} /* FeatureTerm::hasValue */ 




// Makes an independent copy of the Feature Term 
FeatureTerm *FeatureTerm::clone()
{
	FeatureTerm *f;
	List<FeatureTermContainer> old_c;
	List<FeatureTerm> new_c;

	f=cloneInternal(&old_c,&new_c);

	while(!old_c.EmptyP()) old_c.ExtractIni();
	while(!new_c.EmptyP()) new_c.ExtractIni();

	return f;
} /* FeatureTerm::clone */ 


FeatureTerm *FeatureTerm::clone(List<FeatureTerm> *old_nodes,List<FeatureTerm> *new_nodes)
{
	return clone(0,old_nodes,new_nodes);
} /* FeatureTerm::clone */ 


FeatureTerm *FeatureTerm::clone(FTKBase *dm,List<FeatureTerm> *old_nodes,List<FeatureTerm> *new_nodes)
{
	FeatureTerm *f;
	List<FeatureTermContainer> old_c;
	List<FeatureTerm> new_c;
    
    old_nodes->Rewind();
    while(old_nodes->Iterate(f)) old_c.Add(f->m_ft);
    new_nodes->Rewind();
    while(new_nodes->Iterate(f)) new_c.Add(f);
    
	if (dm==0) f=cloneInternal(&old_c,&new_c);
		  else f=cloneInternal(&old_c,&new_c,dm);

//    old_nodes->Delete();
//    new_nodes->Delete();
    
    int l = old_nodes->Length();
    for(int i = 0;i<l;i++) {
        old_c.ExtractIni();
        new_c.ExtractIni();
    }
    
	while(!old_c.EmptyP()) old_nodes->Add(new FeatureTerm(old_c.ExtractIni()));
	while(!new_c.EmptyP()) new_nodes->Add(new FeatureTerm(new_c.ExtractIni()));

	return f;
} /* FeatureTerm::clone */ 



FeatureTerm *FeatureTerm::clone_keepingTrackOfNode(FeatureTerm *node,FeatureTerm **newnode,FTKBase *dm)
{
	int pos;
	FeatureTerm *f;
	List<FeatureTermContainer> old_c;
	List<FeatureTerm> old_c2;
	List<FeatureTerm> new_c;

	if (dm!=0) {
		f=cloneInternal2(&old_c,&old_c2,&new_c,dm);

		if (node!=0) {
//			printf("Searching node: %p,%p\n",node,node->m_ft);
			pos=old_c2.PositionRef(node);
			if (pos==-1) {
				pos=old_c.PositionRef(node->m_ft);
				if (pos==-1) {
					*newnode=0;
				} else {
					*newnode=new_c[pos];
				} /* if */ 
			} else {
				*newnode=new_c[pos];
			} /* if */ 
		} else {
			*newnode=0;
		} /* if */ 

		while(!old_c.EmptyP()) old_c.ExtractIni();
		while(!old_c2.EmptyP()) old_c2.ExtractIni();
		while(!new_c.EmptyP()) new_c.ExtractIni();
	} else {
		f=cloneInternal(&old_c,&new_c);

		if (node!=0) {
			pos=old_c.PositionRef(node->m_ft);
			if (pos==-1) {
				*newnode=0;
			} else {
				*newnode=new_c[pos];
			} /* if */ 
		} else {
			*newnode=0;
		} /* if */ 

		while(!old_c.EmptyP()) old_c.ExtractIni();
		while(!new_c.EmptyP()) new_c.ExtractIni();
	} /* if */ 

	return f;
} /* FeatureTerm::clone_keepingTrackOfNode */ 


FeatureTerm *FeatureTerm::clone_keepingTrackOf2Nodes(FeatureTerm *node1,FeatureTerm **newnode1,FeatureTerm *node2,FeatureTerm **newnode2,FTKBase *dm)
{
	int pos;
	FeatureTerm *f;
	List<FeatureTermContainer> old_c;
	List<FeatureTerm> old_c2;
	List<FeatureTerm> new_c;

	if (dm!=0) {
		f=cloneInternal2(&old_c,&old_c2,&new_c,dm);

		if (node1!=0) {
			pos=old_c2.PositionRef(node1);
			if (pos==-1) {
				pos=old_c.PositionRef(node1->m_ft);
				if (pos==-1) {
					*newnode1=0;
				} else {
					*newnode1=new_c[pos];
				} /* if */ 
			} else {
				*newnode1=new_c[pos];
			} /* if */ 
		} else {
			*newnode1=0;
		} /* if */ 
		if (node2!=0) {
			pos=old_c2.PositionRef(node2);
			if (pos==-1) {
				pos=old_c.PositionRef(node2->m_ft);
				if (pos==-1) {
					*newnode2=0;
				} else {
					*newnode2=new_c[pos];
				} /* if */ 
			} else {
				*newnode2=new_c[pos];
			} /* if */ 
		} else {
			*newnode2=0;
		} /* if */ 

		while(!old_c.EmptyP()) old_c.ExtractIni();
		while(!old_c2.EmptyP()) old_c2.ExtractIni();
		while(!new_c.EmptyP()) new_c.ExtractIni();
	} else {
		f=cloneInternal(&old_c,&new_c);

		if (node1!=0) {
			pos=old_c.PositionRef(node1->m_ft);
			if (pos==-1) {
				*newnode1=0;
			} else {
				*newnode1=new_c[pos];
			} /* if */ 
		} else {
			*newnode1=0;
		} /* if */ 
		if (node2!=0) {
			pos=old_c.PositionRef(node2->m_ft);
			if (pos==-1) {
				*newnode2=0;
			} else {
				*newnode2=new_c[pos];
			} /* if */ 
		} else {
			*newnode2=0;
		} /* if */ 


		while(!old_c.EmptyP()) old_c.ExtractIni();
		while(!new_c.EmptyP()) new_c.ExtractIni();
	} /* if */ 

	return f;
} /* FeatureTerm::clone_keepingTrackOf2Nodes */ 


FeatureTerm *FeatureTerm::cloneInternal(List<class FeatureTermContainer> *old_correspondences,List<FeatureTerm> *new_correspondences)
{
	int pos;

	pos=old_correspondences->PositionRef(m_ft);

	if (pos==-1) {
		FeatureTerm *f=new FeatureTerm((Symbol *)0,(int)0,(Ontology *)0);

		old_correspondences->Add(m_ft);
		new_correspondences->Add(f);

		if (m_ft->m_name!=0) {
			f->m_ft->m_name=new Symbol(m_ft->m_name);
//			printf("Warning! cloning a named feature term: %s\n",m_ft->m_name->get());
		} /* if */ 
		f->m_ft->m_data_type=m_ft->m_data_type;
		f->m_ft->m_sort=m_ft->m_sort;

		switch(m_ft->m_data_type) {
		case DATATYPE_ABSTRACT:
				f->m_ft->m_value.m_ft.m_feature_name=0;
				f->m_ft->m_value.m_ft.m_feature_value=0;
				break;
		case DATATYPE_INTEGER:
				f->m_ft->m_value.m_i=m_ft->m_value.m_i;
				break;
		case DATATYPE_FLOAT:
				f->m_ft->m_value.m_f=m_ft->m_value.m_f;
				break;
		case DATATYPE_SYMBOL:
				if (m_ft->m_value.m_s!=0) {
					f->m_ft->m_value.m_s=new Symbol(m_ft->m_value.m_s);
				} else {
					f->m_ft->m_value.m_s=0;
				} // if
				break;
		case DATATYPE_FEATURETERM: {
					List<FeatureTerm> l;
					FeatureTerm *f2,*f3;
					List<Symbol> l2;
					Symbol *s;

//					f->m_ft->m_value.m_ft=new FeatureTermContainer(m_ft->m_value.m_ft->m_sort,0,0);
					f->m_ft->m_value.m_ft.m_feature_name=new List<Symbol>;
					f->m_ft->m_value.m_ft.m_feature_value=new List<FeatureTerm>;

					l.Instance(*(m_ft->m_value.m_ft.m_feature_value));
					l.Rewind();
					l2.Instance(*(m_ft->m_value.m_ft.m_feature_name));
					l2.Rewind();
					while(l.Iterate(f2) && l2.Iterate(s)) {
						f3=f2->cloneInternal(old_correspondences,new_correspondences);
						f->m_ft->m_value.m_ft.m_feature_value->Add(f3);
						f->m_ft->m_value.m_ft.m_feature_name->Add(new Symbol(s));
					} /* while */ 
				}
				break;
		case DATATYPE_SET: {
					List<FeatureTerm> l;
					FeatureTerm *f2,*f3;

					f->m_ft->m_value.m_set=new List<FeatureTerm>;

					l.Instance(*(m_ft->m_value.m_set));
					l.Rewind();
					while(l.Iterate(f2)) {
						f3=f2->cloneInternal(old_correspondences,new_correspondences);
						f->m_ft->m_value.m_set->Add(f3);
					} /* while */ 
				}
				break;
		case DATATYPE_SPECIAL:
				f->m_ft->m_value.m_special=m_ft->m_value.m_special->clone();
				break;
		} /* switch */ 

		return f;		
	} else {
		return new FeatureTerm((*new_correspondences)[pos]);
	} /* if */ 
} /* FeatureTerm::cloneInternal */ 



// Makes an independent copy of the Feature Term 
FeatureTerm *FeatureTerm::clone(FTKBase *dm)
{
	FeatureTerm *f;
	List<FeatureTermContainer> old_c;
	List<FeatureTerm> new_c;

	if (dm!=0) f=cloneInternal(&old_c,&new_c,dm);
		  else f=cloneInternal(&old_c,&new_c);

	while(!old_c.EmptyP()) old_c.ExtractIni();
	while(!new_c.EmptyP()) new_c.ExtractIni();

	return f;
} /* FeatureTerm::clone */ 


FeatureTerm *FeatureTerm::cloneInternal(List<class FeatureTermContainer> *old_correspondences,List<FeatureTerm> *new_correspondences,FTKBase *dm)
{
	int pos;

	pos=old_correspondences->PositionRef(m_ft);
    
	if (pos==-1) {
		if (!dm->MemberP(this)) {

			FeatureTerm *f=new FeatureTerm((Symbol *)0,(int)0,(Ontology *)0);

			old_correspondences->Add(m_ft);
			new_correspondences->Add(f);

			if (m_ft->m_name!=0) {
				f->m_ft->m_name=new Symbol(m_ft->m_name);
//				printf("Warning(dm)! cloning a named feature term: %s\n",m_ft->m_name->get());
			} /* if */ 
			f->m_ft->m_data_type=m_ft->m_data_type;
			f->m_ft->m_sort=m_ft->m_sort;

			switch(m_ft->m_data_type) {
			case DATATYPE_ABSTRACT:
					f->m_ft->m_value.m_ft.m_feature_name=0;
					f->m_ft->m_value.m_ft.m_feature_value=0;
					break;
			case DATATYPE_INTEGER:
					f->m_ft->m_value.m_i=m_ft->m_value.m_i;
					break;
			case DATATYPE_FLOAT:
					f->m_ft->m_value.m_f=m_ft->m_value.m_f;
					break;
			case DATATYPE_SYMBOL:
					if (m_ft->m_value.m_s!=0) f->m_ft->m_value.m_s=new Symbol(m_ft->m_value.m_s);
										 else f->m_ft->m_value.m_s=0;
					break;
			case DATATYPE_FEATURETERM: {
						List<FeatureTerm> l;
						FeatureTerm *f2,*f3;
						List<Symbol> l2;
						Symbol *s;

						f->m_ft->m_value.m_ft.m_feature_name=new List<Symbol>;
						f->m_ft->m_value.m_ft.m_feature_value=new List<FeatureTerm>;

						l.Instance(*(m_ft->m_value.m_ft.m_feature_value));
						l.Rewind();
						l2.Instance(*(m_ft->m_value.m_ft.m_feature_name));
						l2.Rewind();
						while(l.Iterate(f2) && l2.Iterate(s)) {
							f3=f2->cloneInternal(old_correspondences,new_correspondences,dm);
							f->m_ft->m_value.m_ft.m_feature_value->Add(f3);
							f->m_ft->m_value.m_ft.m_feature_name->Add(new Symbol(s));
						} /* while */ 
					}
					break;
			case DATATYPE_SET: {
						List<FeatureTerm> l;
						FeatureTerm *f2,*f3;

						f->m_ft->m_value.m_set=new List<FeatureTerm>;

						l.Instance(*(m_ft->m_value.m_set));
						l.Rewind();
						while(l.Iterate(f2)) {
							f3=f2->cloneInternal(old_correspondences,new_correspondences,dm);
							f->m_ft->m_value.m_set->Add(f3);
						} /* while */ 
					}
					break;
			case DATATYPE_SPECIAL:
					f->m_ft->m_value.m_special=m_ft->m_value.m_special->clone(dm);
					break;
			} /* switch */ 
			return f;
		} else {
			return new FeatureTerm(m_ft);
		} /* if */ 
	} else {
		return new FeatureTerm((*new_correspondences)[pos]);
	} /* if */ 
} /* FeatureTerm::cloneInternal */ 


FeatureTerm *FeatureTerm::cloneInternalUnnamed(List<class FeatureTermContainer> *old_correspondences,List<FeatureTerm> *new_correspondences)
{
	int pos;

	pos=old_correspondences->PositionRef(m_ft);

	if (pos==-1) {
		FeatureTerm *f=new FeatureTerm((Symbol *)0,(int)0,(Ontology *)0);

		old_correspondences->Add(m_ft);
		new_correspondences->Add(f);

		f->m_ft->m_data_type=m_ft->m_data_type;
		f->m_ft->m_sort=m_ft->m_sort;

		switch(m_ft->m_data_type) {
		case -1:
				f->m_ft->m_value.m_ft.m_feature_name=0;
				f->m_ft->m_value.m_ft.m_feature_value=0;
				break;
		case 0:
				f->m_ft->m_value.m_i=m_ft->m_value.m_i;
				break;
		case 1:
				f->m_ft->m_value.m_f=m_ft->m_value.m_f;
				break;
		case 2:
				f->m_ft->m_value.m_s=new Symbol(m_ft->m_value.m_s);
				break;
		case 3: {
					List<FeatureTerm> l;
					FeatureTerm *f2,*f3;
					List<Symbol> l2;
					Symbol *s;

//					f->m_ft->m_value.m_ft=new FeatureTermContainer(m_ft->m_value.m_ft->m_sort,0,0);
					f->m_ft->m_value.m_ft.m_feature_name=new List<Symbol>;
					f->m_ft->m_value.m_ft.m_feature_value=new List<FeatureTerm>;

					l.Instance(*(m_ft->m_value.m_ft.m_feature_value));
					l.Rewind();
					l2.Instance(*(m_ft->m_value.m_ft.m_feature_name));
					l2.Rewind();
					while(l.Iterate(f2) && l2.Iterate(s)) {
						f3=f2->cloneInternalUnnamed(old_correspondences,new_correspondences);
						f->m_ft->m_value.m_ft.m_feature_value->Add(f3);
						f->m_ft->m_value.m_ft.m_feature_name->Add(new Symbol(s));
					} /* while */ 
				}
				break;
		case 4: {
					List<FeatureTerm> l;
					FeatureTerm *f2,*f3;

					f->m_ft->m_value.m_set=new List<FeatureTerm>;

					l.Instance(*(m_ft->m_value.m_set));
					l.Rewind();
					while(l.Iterate(f2)) {
						f3=f2->cloneInternalUnnamed(old_correspondences,new_correspondences);
						f->m_ft->m_value.m_set->Add(f3);
					} /* while */ 
				}
				break;
		case DATATYPE_SPECIAL:
				f->m_ft->m_value.m_special=m_ft->m_value.m_special->clone();
				break;
		} /* switch */ 

		return f;		
	} else {
		return new FeatureTerm((*new_correspondences)[pos]);
	} /* if */ 
} /* FeatureTerm::cloneInternalUnnamed */ 



// Makes an independent copy of the Feature Term 
FeatureTerm *FeatureTerm::cloneUnnamed(FTKBase *dm)
{
	FeatureTerm *f;
	List<FeatureTermContainer> old_c;
	List<FeatureTerm> new_c;

	if (dm!=0) f=cloneInternalUnnamed(&old_c,&new_c,dm);
		  else f=cloneInternalUnnamed(&old_c,&new_c);

	while(!old_c.EmptyP()) old_c.ExtractIni();
	while(!new_c.EmptyP()) new_c.ExtractIni();

	return f;
} /* FeatureTerm::cloneUnnamed */ 


FeatureTerm *FeatureTerm::cloneInternalUnnamed(List<class FeatureTermContainer> *old_correspondences,List<FeatureTerm> *new_correspondences,FTKBase *dm)
{
	int pos;

	pos=old_correspondences->PositionRef(m_ft);

	if (pos==-1) {
		if (!dm->MemberP(this)) {

			FeatureTerm *f=new FeatureTerm((Symbol *)0,(int)0,(Ontology *)0);

			old_correspondences->Add(m_ft);
			new_correspondences->Add(f);

			f->m_ft->m_data_type=m_ft->m_data_type;
			f->m_ft->m_sort=m_ft->m_sort;

			switch(m_ft->m_data_type) {
			case -1:
					f->m_ft->m_value.m_ft.m_feature_name=0;
					f->m_ft->m_value.m_ft.m_feature_value=0;
					break;
			case 0:
					f->m_ft->m_value.m_i=m_ft->m_value.m_i;
					break;
			case 1:
					f->m_ft->m_value.m_f=m_ft->m_value.m_f;
					break;
			case 2:
					f->m_ft->m_value.m_s=new Symbol(m_ft->m_value.m_s);
					break;
			case 3: {
						List<FeatureTerm> l;
						FeatureTerm *f2,*f3;
						List<Symbol> l2;
						Symbol *s;

						f->m_ft->m_value.m_ft.m_feature_name=new List<Symbol>;
						f->m_ft->m_value.m_ft.m_feature_value=new List<FeatureTerm>;

						l.Instance(*(m_ft->m_value.m_ft.m_feature_value));
						l.Rewind();
						l2.Instance(*(m_ft->m_value.m_ft.m_feature_name));
						l2.Rewind();
						while(l.Iterate(f2) && l2.Iterate(s)) {
							f3=f2->cloneInternalUnnamed(old_correspondences,new_correspondences,dm);
							f->m_ft->m_value.m_ft.m_feature_value->Add(f3);
							f->m_ft->m_value.m_ft.m_feature_name->Add(new Symbol(s));
						} /* while */ 
					}
					break;
			case 4: {
						List<FeatureTerm> l;
						FeatureTerm *f2,*f3;

						f->m_ft->m_value.m_set=new List<FeatureTerm>;

						l.Instance(*(m_ft->m_value.m_set));
						l.Rewind();
						while(l.Iterate(f2)) {
							f3=f2->cloneInternalUnnamed(old_correspondences,new_correspondences,dm);
							f->m_ft->m_value.m_set->Add(f3);
						} /* while */ 
					}
					break;
			case DATATYPE_SPECIAL:
					f->m_ft->m_value.m_special=m_ft->m_value.m_special->clone(dm);
					break;
			} /* switch */ 
			return f;
		} else {
			return new FeatureTerm(m_ft);
		} /* if */ 
	} else {
		return new FeatureTerm((*new_correspondences)[pos]);
	} /* if */ 
} /* FeatureTerm::cloneInternalUnnamed */ 




FeatureTerm *FeatureTerm::cloneInternal2(List<FeatureTermContainer> *old_correspondences,List<FeatureTerm> *old_correspondences2,List<FeatureTerm> *new_correspondences,class FTKBase *dm)
{
	int pos;

//	printf("Considering node: %p, %p\n",this,m_ft);

	pos=old_correspondences->PositionRef(m_ft);

	if (pos==-1) {
		if (!dm->MemberP(this)) {

			FeatureTerm *f=new FeatureTerm((Symbol *)0,(int)0,(Ontology *)0);

			old_correspondences->Add(m_ft);
			old_correspondences2->Add(this);
			new_correspondences->Add(f);

			if (m_ft->m_name!=0) {
				f->m_ft->m_name=new Symbol(m_ft->m_name);
//				printf("Warning2! cloning a named feature term: %s\n",m_ft->m_name->get());
			} /* if */ 
			f->m_ft->m_data_type=m_ft->m_data_type;
			f->m_ft->m_sort=m_ft->m_sort;

			switch(m_ft->m_data_type) {
			case -1:
					f->m_ft->m_value.m_ft.m_feature_name=0;
					f->m_ft->m_value.m_ft.m_feature_value=0;
					break;
			case 0:
					f->m_ft->m_value.m_i=m_ft->m_value.m_i;
					break;
			case 1:
					f->m_ft->m_value.m_f=m_ft->m_value.m_f;
					break;
			case 2:
					if (m_ft->m_value.m_s!=0) f->m_ft->m_value.m_s=new Symbol(m_ft->m_value.m_s);
									     else f->m_ft->m_value.m_s=0;
					break;
			case 3: {
						List<FeatureTerm> l;
						FeatureTerm *f2,*f3;
						List<Symbol> l2;
						Symbol *s;

						f->m_ft->m_value.m_ft.m_feature_name=new List<Symbol>;
						f->m_ft->m_value.m_ft.m_feature_value=new List<FeatureTerm>;

						l.Instance(*(m_ft->m_value.m_ft.m_feature_value));
						l.Rewind();
						l2.Instance(*(m_ft->m_value.m_ft.m_feature_name));
						l2.Rewind();
						while(l.Iterate(f2) && l2.Iterate(s)) {
							f3=f2->cloneInternal2(old_correspondences,old_correspondences2,new_correspondences,dm);
							f->m_ft->m_value.m_ft.m_feature_value->Add(f3);
							f->m_ft->m_value.m_ft.m_feature_name->Add(new Symbol(s));
						} /* while */ 
					}
					break;
			case 4: {
						List<FeatureTerm> l;
						FeatureTerm *f2,*f3;

						f->m_ft->m_value.m_set=new List<FeatureTerm>;

						l.Instance(*(m_ft->m_value.m_set));
						l.Rewind();
						while(l.Iterate(f2)) {
							f3=f2->cloneInternal2(old_correspondences,old_correspondences2,new_correspondences,dm);
							f->m_ft->m_value.m_set->Add(f3);
						} /* while */ 
					}
					break;
			case DATATYPE_SPECIAL:
					f->m_ft->m_value.m_special=m_ft->m_value.m_special->clone(dm);
					break;
			} /* switch */ 
			return f;
		} else {
			FeatureTerm *f=new FeatureTerm(m_ft);
			old_correspondences->Add(m_ft);
			old_correspondences2->Add(this);
			new_correspondences->Add(f);

			return f;
		} /* if */ 
	} else {
		FeatureTerm *f=new FeatureTerm((*new_correspondences)[pos]);
		old_correspondences->Add(m_ft);
		old_correspondences2->Add(this);
		new_correspondences->Add(f);

		return f;
	} /* if */ 
} /*  FeatureTerm::cloneInternal2 */ 



bool FeatureTerm::operator==(FeatureTerm &f)
{

	if ((m_ft->m_data_type==DATATYPE_INTEGER && (m_ft->m_value.m_i.m_type==0 || f.m_ft->m_value.m_i.m_type==0)) ||
        (m_ft->m_data_type==DATATYPE_FLOAT && (m_ft->m_value.m_f.m_type==0 || f.m_ft->m_value.m_f.m_type==0)) ||
		(m_ft->m_data_type==DATATYPE_SYMBOL && (m_ft->m_value.m_s!=0 || f.m_ft->m_value.m_s!=0))) 
			return (subsumes(&f) && f.subsumes(this));	
	   else return m_ft==f.m_ft;

} /* FeatureTerm::operator== */ 


bool FeatureTerm::equivalents(FeatureTerm *f)
{
	return (subsumes(f) && f->subsumes(this));
} /* FeatureTerm::equivalents */ 


bool FeatureTerm::same(FeatureTerm *f)
{
	if (f==0) return false;
	return m_ft==f->m_ft;
} /* FeatureTerm::same */ 



void FeatureTerm::get_paths(List< List<Symbol> > *l)
{
	if (m_ft->m_data_type==DATATYPE_FEATURETERM) {
		List<Symbol> *path=new List<Symbol>;
		get_paths_internal(path,l);
		delete path;
	} /* if */ 

	if (m_ft->m_data_type==DATATYPE_SET) {
		List<FeatureTerm> l2;
		FeatureTerm *f;

		l2.Instance(*(m_ft->m_value.m_set));
		l2.Rewind();
		while(l2.Iterate(f)) f->get_paths(l);
	} /* if */ 
} /* FeatureTerm::get_paths */ 



void FeatureTerm::get_paths_internal(List<Symbol> *current_path,List< List<Symbol> > *l)
{
	if (m_ft->m_data_type==DATATYPE_FEATURETERM && !m_ft->m_value.m_ft.m_feature_name->EmptyP()) {
		List<Symbol> *path;
		List<Symbol> fn;
		Symbol *n;
		List<FeatureTerm> fv;
		FeatureTerm *f;

		fn.Instance(*(m_ft->m_value.m_ft.m_feature_name));
		fn.Rewind();
		fv.Instance(*(m_ft->m_value.m_ft.m_feature_value));
		fv.Rewind();

		while(fn.Iterate(n) &&
			  fv.Iterate(f)) {
			path=new List<Symbol>();
			path->Copy(*current_path);
			path->Add(new Symbol(n));
			f->get_paths_internal(path,l);
			delete path;
		} /* while */ 

	} else if (m_ft->m_data_type==DATATYPE_SET) {
		List<FeatureTerm> l2;
		FeatureTerm *f;

		l2.Instance(*(m_ft->m_value.m_set));
		l2.Rewind();
		while(l2.Iterate(f)) f->get_paths_internal(current_path,l);
	} else {
		/* Add the path: */ 
		if (!l->MemberP(current_path)) {
			List<Symbol> *np=new List<Symbol>();
			np->Copy(*current_path);
			l->Add(np);
		} /* if */ 
	} /* if */ 
} /* FeatureTerm::get_paths_internal */ 


bool FeatureTerm::isAbstract(void)
{
	if (m_ft==0) return false;
	if (m_ft->m_data_type==DATATYPE_ABSTRACT) return true;

	return false;
} /* FeatureTerm::isAbstract */ 


bool FeatureTerm::isInt(void)
{
	if (m_ft==0) return false;
	if (m_ft->m_data_type==DATATYPE_INTEGER) return true;

	return false;
} /* FeatureTerm::isInt */ 



bool FeatureTerm::isFloat(void)
{
	if (m_ft==0) return false;
	if (m_ft->m_data_type==DATATYPE_FLOAT) return true;

	return false;
} /* FeatureTerm::isFloat */ 


bool FeatureTerm::isSymbol(void)
{
	if (m_ft==0) return false;
	if (m_ft->m_data_type==DATATYPE_SYMBOL) return true;

	return false;
} /* FeatureTerm::isSymbol */ 


bool FeatureTerm::isFeatureTerm(void)
{
	if (m_ft==0) return false;
	if (m_ft->m_data_type==DATATYPE_FEATURETERM) return true;

	return false;
} /* FeatureTerm::isFeatureTerm */ 


bool FeatureTerm::isSet(void)
{
	if (m_ft==0) return false;
	if (m_ft->m_data_type==DATATYPE_SET) return true;

	return false;
} /* FeatureTerm::isSet */ 


bool FeatureTerm::isSpecial(void)
{
	if (m_ft==0) return false;
	if (m_ft->m_data_type==DATATYPE_SPECIAL) return true;

	return false;
} /* FeatureTerm::isSpecial */ 



void FeatureTerm::delete_circular_structure(List<FeatureTermContainer> *todelete,List<FeatureTerm> *expanded,List<FeatureTerm> *delayed)
{
//	printf("Visiting %p %s %i\n",m_ft,(m_ft->m_name==0 ? "???":m_ft->m_name->get()),m_ft->m_reference_count);
	if (m_ft->m_reference_count>0) {
//		m_ft->m_reference_count--; /* (1) */ 
		if (todelete->MemberRefP(m_ft)) {
//			m_ft->m_reference_count--; /* (3) */ 

			if (!expanded->MemberP(this)) {
				expanded->Add(this);
				if (m_ft->m_data_type==DATATYPE_FEATURETERM && m_ft->m_value.m_ft.m_feature_value!=0) {
					FeatureTerm *ft;
					List<FeatureTerm> l_features;
//					printf("  a FT with %i features\n",m_ft->m_value.m_ft->m_feature_value.Length());

					l_features.Instance(*(m_ft->m_value.m_ft.m_feature_value));
					l_features.Rewind();
					while(l_features.Iterate(ft)) {
						ft->delete_circular_structure(todelete,expanded,delayed);
					} /* while */ 

					m_ft->m_value.m_ft.m_feature_name->Delete();
					while(!m_ft->m_value.m_ft.m_feature_value->EmptyP()) {
						ft=m_ft->m_value.m_ft.m_feature_value->ExtractIni();
						if (expanded->MemberRefP(ft)) {
							delayed->Add(ft);
						} else {
							ft->m_ft=0;
							delete ft;
						} /* if */ 
					} /* while */ 
				
				} /* if */ 
				if (m_ft->m_data_type==DATATYPE_SET && m_ft->m_value.m_set!=0) {
					FeatureTerm *ft;
					List<FeatureTerm> l_set;
//					printf("  a SET with %i feature terms\n",m_ft->m_value.m_set->Length());

					l_set.Instance(*(m_ft->m_value.m_set));
					l_set.Rewind();
					while(l_set.Iterate(ft)) {
						ft->delete_circular_structure(todelete,expanded,delayed);
					} /* while */ 

					while(!m_ft->m_value.m_set->EmptyP()) {
						ft=m_ft->m_value.m_set->ExtractIni();
						if (expanded->MemberRefP(ft)) {
							delayed->Add(ft);
						} else {
							ft->m_ft=0;
							delete ft;
						} /* if */ 
					} /* while */ 
				
				} /* if */ 

				m_ft->m_reference_count--; /* (2) */ 
				if (m_ft->m_reference_count<=0) {
//					printf("Deleting %p %s %i\n",m_ft,(m_ft->m_name==0 ? "???":m_ft->m_name->get()),m_ft->m_reference_count);
					delete m_ft;
					m_ft=0;
				} /* if */ 

				expanded->DeleteElement(this);
			} else { 
				m_ft->m_reference_count--;	/* (2) */ 
			} /* if */ 
		} else { 
			m_ft->m_reference_count--;	/* (2) */ 
		} /* if */ 
	} /* if */ 
} /* FeatureTerm::delete_circular_structure */ 


List<FeatureTerm> *FeatureTerm::readPath(List<Symbol> *path)
{
	List<FeatureTerm> *l1,*l2;
	FeatureTerm *ft,*ft2;
	List<Symbol> path_l;
	Symbol *feature;

	l1=new List<FeatureTerm>;
	l2=new List<FeatureTerm>;

	l1->Add(new FeatureTerm(this));

	path_l.Instance(*path);
	path_l.Rewind();
	while(path_l.Iterate(feature)) {
		
		while(!l1->EmptyP()) {
			ft=l1->ExtractIni();
			if (ft->m_ft!=0) {
				if (ft->m_ft->m_data_type==DATATYPE_FEATURETERM) {
					ft2=ft->featureValue(feature);
					if (ft2!=0) l2->Add(ft2);
				} /* if */ 

				if (ft->m_ft->m_data_type==DATATYPE_SET) {
					List<FeatureTerm> l;
					FeatureTerm *ft3;

					l.Instance(*(ft->m_ft->m_value.m_set));
					l.Rewind();
					while(l.Iterate(ft2)) {
						if (ft2->m_ft->m_data_type==DATATYPE_FEATURETERM) {
							ft3=ft2->featureValue(feature);
							if (ft3!=0) l2->Add(ft3);
						} /* if */ 
					} /* while */ 
				} /* if */ 
			} /* if */ 
			delete ft;
		} /* while */ 

		delete l1;
		l1=l2;
		l2=new List<FeatureTerm>;
	} /* while */ 

	delete l2;
	return l1;
} /* FeatureTerm::readPath */ 


int FeatureTerm::size(void)
{
	FeatureTerm *ft;
	List<FeatureTermContainer> open_nodes,nodes;
	FeatureTermContainer *node;
	int n_nodes=0;

	open_nodes.Add(m_ft);

	while(!open_nodes.EmptyP()) {
		node=open_nodes.ExtractIni();

		nodes.Add(node);

		if (node->m_data_type==DATATYPE_FEATURETERM) {
			List<FeatureTerm> l_features;
			List<Symbol> l_fnames;
			Symbol *fname;

			l_features.Instance(*(node->m_value.m_ft.m_feature_value));
			l_fnames.Instance(*(node->m_value.m_ft.m_feature_name));
			l_features.Rewind();
			l_fnames.Rewind();
			while(l_features.Iterate(ft) &&
				  l_fnames.Iterate(fname)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) open_nodes.Add(ft->m_ft);
			} /* while */ 
		} /* if */ 

		if (node->m_data_type==DATATYPE_SET) {
			List<FeatureTerm> l_features;

			l_features.Instance(*(node->m_value.m_set));
			l_features.Rewind();
			while(l_features.Iterate(ft)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) open_nodes.Add(ft->m_ft);
			} /* while */ 
		} /* if */ 
	} /* while */ 
	
	n_nodes=nodes.Length();

	while(!nodes.EmptyP()) nodes.ExtractIni();

	return n_nodes;
} /* FeatureTerm::size */ 


int FeatureTerm::depth(void)
{
	FeatureTerm *ft;
	List<FeatureTermContainer> open_nodes,nodes;
	List< List<Symbol> > open_paths,paths;
	List<Symbol> *path,*path2;
	FeatureTermContainer *node;
	int max_depth=0;
	Symbol *path_feature;

	open_nodes.Add(m_ft);
	open_paths.Add(new List<Symbol>);

	while(!open_nodes.EmptyP()) {
		node=open_nodes.ExtractIni();
		path=open_paths.ExtractIni();

		nodes.Add(node);
		paths.Add(path);

		if (node->m_data_type==DATATYPE_FEATURETERM) {
			List<FeatureTerm> l_features;
			List<Symbol> l_fnames;
			Symbol *fname;

			l_features.Instance(*(node->m_value.m_ft.m_feature_value));
			l_fnames.Instance(*(node->m_value.m_ft.m_feature_name));
			l_features.Rewind();
			l_fnames.Rewind();
			while(l_features.Iterate(ft) &&
				  l_fnames.Iterate(fname)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) {

					path2=new List<Symbol>;
					path->Rewind();
					while(path->Iterate(path_feature)) path2->Add(path_feature);
					path2->Add(fname);
					
					open_nodes.Add(ft->m_ft);
					open_paths.Add(path2);
				} /* if */ 
			} /* while */ 
		} /* if */ 

		if (node->m_data_type==DATATYPE_SET) {
			List<FeatureTerm> l_features;

			l_features.Instance(*(node->m_value.m_set));
			l_features.Rewind();
			while(l_features.Iterate(ft)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) {
				
					path2=new List<Symbol>;
					path->Rewind();
					while(path->Iterate(path_feature)) path2->Add(path_feature);

					open_nodes.Add(ft->m_ft);
					open_paths.Add(path2);
				} /* if */ 
			} /* while */ 
		} /* if */ 
	} /* while */ 
	
	while(!nodes.EmptyP()) nodes.ExtractIni();
	while(!paths.EmptyP()) {
		path=paths.ExtractIni();
		if (path->Length()>max_depth) max_depth=path->Length();
		while(!path->EmptyP()) path->ExtractIni();
		delete path;
	} /* while */ 

	return max_depth;
} /* FeatureTerm::depth */ 



void FeatureTerm::nodes(List<FeatureTerm> **res)
{
	List<FeatureTerm> *result=new List<FeatureTerm>;
	FeatureTerm *ft;
	List<FeatureTermContainer> open_nodes,nodes;
	FeatureTermContainer *node;

	result->Add(this);
	open_nodes.Add(m_ft);

	while(!open_nodes.EmptyP()) {
		node=open_nodes.ExtractIni();

		nodes.Insert(node);

		if (node->m_data_type==DATATYPE_FEATURETERM) {
			List<FeatureTerm> l_features;
			List<Symbol> l_fnames;
			Symbol *fname;

			l_features.Instance(*(node->m_value.m_ft.m_feature_value));
			l_fnames.Instance(*(node->m_value.m_ft.m_feature_name));
			l_features.Rewind();
			l_fnames.Rewind();
			while(l_features.Iterate(ft) &&
				  l_fnames.Iterate(fname)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) {
					open_nodes.Add(ft->m_ft);
					result->Add(ft);
				} /* if */ 
			} /* while */ 
		} /* if */ 

		if (node->m_data_type==DATATYPE_SET) {
			List<FeatureTerm> l_features;

			l_features.Instance(*(node->m_value.m_set));
			l_features.Rewind();
			while(l_features.Iterate(ft)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) {
					open_nodes.Add(ft->m_ft);
					result->Add(ft);
				} /* if */ 
			} /* while */ 
		} /* if */ 
	} /* while */ 
	
	while(!nodes.EmptyP()) nodes.ExtractIni();

	*res=result;
} /* FeatureTerm::nodes */ 


void FeatureTerm::nodesPaths(List<FeatureTerm> **nl,List<Path> **pl)
{
	List<FeatureTerm> *resultn=new List<FeatureTerm>;
	List<Path> *resultp=new List<Path>;
	FeatureTerm *ft;
	List<FeatureTermContainer> open_nodes,nodes;
	List<Path> open_paths,paths;
	Path *path,*path2;
	FeatureTermContainer *node;

	resultn->Add(this);
	resultp->Add(new Path);
	open_nodes.Add(m_ft);
	open_paths.Add(new Path);

	while(!open_nodes.EmptyP()) {
		node=open_nodes.ExtractIni();
		path=open_paths.ExtractIni();
		
		nodes.Insert(node);
		paths.Insert(path);

		if (node->m_data_type==DATATYPE_FEATURETERM) {
			List<FeatureTerm> l_features;
			List<Symbol> l_fnames;
			Symbol *fname;

			l_features.Instance(*(node->m_value.m_ft.m_feature_value));
			l_fnames.Instance(*(node->m_value.m_ft.m_feature_name));
			l_features.Rewind();
			l_fnames.Rewind();
			while(l_features.Iterate(ft) &&
				  l_fnames.Iterate(fname)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) {

					path2=new Path;
					path2->Copy(*path);
					path2->Add(new Symbol(fname));
					
					open_paths.Add(path2);
					open_nodes.Add(ft->m_ft);
					resultn->Add(ft);
					resultp->Add(new Path(*path2));
				} /* if */ 
			} /* while */ 
		} /* if */ 

		if (node->m_data_type==DATATYPE_SET) {
			List<FeatureTerm> l_features;

			l_features.Instance(*(node->m_value.m_set));
			l_features.Rewind();
			while(l_features.Iterate(ft)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) {

					path2=new Path;
					path2->Copy(*path);

					open_paths.Add(path2);
					open_nodes.Add(ft->m_ft);
					resultn->Add(ft);
					resultp->Add(new Path(*path2));
				} /* if */ 
			} /* while */ 
		} /* if */ 
	} /* while */ 
	
	while(!nodes.EmptyP()) nodes.ExtractIni();

	if (nl!=0) {
		*nl=resultn;
	} else {
		delete resultn;
	} /* if */ 
	if (pl!=0) {
		*pl=resultp;
	} else {
		delete resultp;
	} /* if */ 
} /* FeatureTerm::nodesPaths */ 


void FeatureTerm::nodesPathsSorts(List<FeatureTerm> **nl,List<Path> **pl,List<Sort> **sl,Ontology *o)
{
	List<FeatureTerm> *resultn=new List<FeatureTerm>;
	List<Path> *resultp=new List<Path>;
	List<Sort> *results=new List<Sort>;
	FeatureTerm *ft;
	List<FeatureTermContainer> open_nodes,nodes;
	List<Path> open_paths,paths;
	List<Sort> open_sorts,sorts;
	Path *path,*path2;
	FeatureTermContainer *node;
	Sort *sort;

	resultn->Add(this);
	resultp->Add(new Path);
	results->Add(o->get_sort("any"));
	open_nodes.Add(m_ft);
	open_paths.Add(new Path);
	open_sorts.Add(o->get_sort("any"));

	while(!open_nodes.EmptyP()) {
		node=open_nodes.ExtractIni();
		path=open_paths.ExtractIni();
		sort=open_sorts.ExtractIni();
		
		nodes.Insert(node);
		paths.Insert(path);
		sorts.Insert(sort);

		if (node->m_data_type==DATATYPE_FEATURETERM) {
			List<FeatureTerm> l_features;
			List<Symbol> l_fnames;
			Symbol *fname;

			l_features.Instance(*(node->m_value.m_ft.m_feature_value));
			l_fnames.Instance(*(node->m_value.m_ft.m_feature_name));
			l_features.Rewind();
			l_fnames.Rewind();
			while(l_features.Iterate(ft) &&
				  l_fnames.Iterate(fname)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) {

					path2=new Path;
					path2->Copy(*path);
					path2->Add(new Symbol(fname));
					
					open_paths.Add(path2);
					open_nodes.Add(ft->m_ft);
					open_sorts.Add(node->m_sort->featureSort(fname));
					resultn->Add(ft);
					resultp->Add(new Path(*path2));
					results->Add(node->m_sort->featureSort(fname));
				} /* if */ 
			} /* while */ 
		} /* if */ 

		if (node->m_data_type==DATATYPE_SET) {
			List<FeatureTerm> l_features;

			l_features.Instance(*(node->m_value.m_set));
			l_features.Rewind();
			while(l_features.Iterate(ft)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) {

					path2=new Path;
					path2->Copy(*path);

					open_paths.Add(path2);
					open_nodes.Add(ft->m_ft);
					open_sorts.Add(sort);
					resultn->Add(ft);
					resultp->Add(new Path(*path2));
					results->Add(sort);
				} /* if */ 
			} /* while */ 
		} /* if */ 
	} /* while */ 
	
	while(!nodes.EmptyP()) nodes.ExtractIni();
	while(!sorts.EmptyP()) sorts.ExtractIni();

	if (nl!=0) {
		*nl=resultn;
	} else {
		delete resultn;
	} /* if */ 
	if (pl!=0) {
		*pl=resultp;
	} else {
		delete resultp;
	} /* if */ 
	if (sl!=0) {
		*sl=results;
	} else {
		delete results;
	} /* if */ 
} /* FeatureTerm::nodesPathsSorts */ 



void FeatureTerm::nodesAllPaths(List<FeatureTerm> **nl,List< List<Path> > **pl)
{
	int pos;
	List<FeatureTerm> *resultn=new List<FeatureTerm>;
	List< List<Path> > *resultp=new List< List<Path> >;
	List<Path> *pathl;
	FeatureTerm *ft;
	List<FeatureTermContainer> open_nodes,nodes;
	List<Path> open_paths,paths;
	Path *path,*path2;
	FeatureTermContainer *node;

	resultn->Add(this);
	pathl=new List<Path>;
	pathl->Add(new Path);
	resultp->Add(pathl);
	open_nodes.Add(m_ft);
	open_paths.Add(new Path);

	while(!open_nodes.EmptyP()) {
		node=open_nodes.ExtractIni();
		path=open_paths.ExtractIni();
		
		nodes.Insert(node);
		paths.Insert(path);

		if (node->m_data_type==DATATYPE_FEATURETERM) {
			List<FeatureTerm> l_features;
			List<Symbol> l_fnames;
			Symbol *fname;

			l_features.Instance(*(node->m_value.m_ft.m_feature_value));
			l_fnames.Instance(*(node->m_value.m_ft.m_feature_name));
			l_features.Rewind();
			l_fnames.Rewind();
			while(l_features.Iterate(ft) &&
				  l_fnames.Iterate(fname)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) {

					path2=new Path;
					path2->Copy(*path);
					path2->Add(new Symbol(fname));
					
					open_paths.Add(path2);
					open_nodes.Add(ft->m_ft);
				} /* if */ 

				/* add another path to the node: */ 
				pos=resultn->PositionRef(ft);
				if (pos==-1) {
					path2=new Path;
					path2->Copy(*path);
					path2->Add(new Symbol(fname));
					resultn->Add(ft);
					pathl=new List<Path>;
					pathl->Add(path2);
					resultp->Add(pathl);
				} else {
					path2=new Path;
					path2->Copy(*path);
					path2->Add(new Symbol(fname));
					pathl=resultp->operator [](pos);
					pathl->Add(path2);
				} /* if */ 		
			} /* while */ 
		} /* if */ 

		if (node->m_data_type==DATATYPE_SET) {
			List<FeatureTerm> l_features;

			l_features.Instance(*(node->m_value.m_set));
			l_features.Rewind();
			while(l_features.Iterate(ft)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) {

					path2=new Path;
					path2->Copy(*path);

					open_paths.Add(path2);
					open_nodes.Add(ft->m_ft);
				} /* if */ 

				/* add another path to the node: */ 
				pos=resultn->PositionRef(ft);
				if (pos==-1) {
					path2=new Path;
					path2->Copy(*path);
					resultn->Add(ft);
					pathl=new List<Path>;
					pathl->Add(path2);
					resultp->Add(pathl);
				} else {
					path2=new Path;
					path2->Copy(*path);
					pathl=resultp->operator [](pos);
					pathl->Add(path2);
				} /* if */ 	
			} /* while */ 
		} /* if */ 
	} /* while */ 
	
	while(!nodes.EmptyP()) nodes.ExtractIni();

	if (nl!=0) {
		*nl=resultn;
	} else {
		delete resultn;
	} /* if */ 
	if (pl!=0) {
		*pl=resultp;
	} else {
		delete resultp;
	} /* if */ 
} /* FeatureTerm::nodesAllPaths */ 


void FeatureTerm::nodesAllPathsSorts(List<FeatureTerm> **nl,List< List<Path> > **pl,List< List<Sort> > **sl,Ontology *o)
{
	int pos;
	List<FeatureTerm> *resultn=new List<FeatureTerm>;
	List< List<Path> > *resultp=new List< List<Path> >;
	List<Path> *pathl;
	List< List<Sort> > *results=new List< List<Sort> >;
	List<Sort> *sortl;
	FeatureTerm *ft;
	List<FeatureTermContainer> open_nodes,nodes;
	List<Path> open_paths,paths;
	List<Sort> open_sorts,sorts;
	Path *path,*path2;
	FeatureTermContainer *node;
	Sort *sort;

	resultn->Add(this);
	pathl=new List<Path>;
	pathl->Add(new Path);
	resultp->Add(pathl);
	sortl=new List<Sort>;
	sortl->Add(o->get_sort("any"));
	results->Add(sortl);
	open_nodes.Add(m_ft);
	open_paths.Add(new Path);
	open_sorts.Add(o->get_sort("any"));

	while(!open_nodes.EmptyP()) {
		node=open_nodes.ExtractIni();
		path=open_paths.ExtractIni();
		sort=open_sorts.ExtractIni();
		
		nodes.Insert(node);
		paths.Insert(path);
		sorts.Insert(sort);

		if (node->m_data_type==DATATYPE_FEATURETERM) {
			List<FeatureTerm> l_features;
			List<Symbol> l_fnames;
			Symbol *fname;

			l_features.Instance(*(node->m_value.m_ft.m_feature_value));
			l_fnames.Instance(*(node->m_value.m_ft.m_feature_name));
			l_features.Rewind();
			l_fnames.Rewind();
			while(l_features.Iterate(ft) &&
				  l_fnames.Iterate(fname)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) {

					path2=new Path;
					path2->Copy(*path);
					path2->Add(new Symbol(fname));

					open_paths.Add(path2);
					open_nodes.Add(ft->m_ft);
					open_sorts.Add(node->m_sort->featureSort(fname));
				} /* if */ 

				/* add another path to the node: */ 
				pos=resultn->PositionRef(ft);
				if (pos==-1) {
					path2=new Path;
					path2->Copy(*path);
					path2->Add(new Symbol(fname));
					resultn->Add(ft);
					pathl=new List<Path>;
					pathl->Add(path2);
					resultp->Add(pathl);
					sortl=new List<Sort>;
					sortl->Add(node->m_sort->featureSort(fname));
					results->Add(sortl);
				} else {
					path2=new Path;
					path2->Copy(*path);
					path2->Add(new Symbol(fname));
					pathl=resultp->operator [](pos);
					pathl->Add(path2);
					sortl=results->operator [](pos);
					sortl->Add(node->m_sort->featureSort(fname));
				} /* if */ 		
			} /* while */ 
		} /* if */ 

		if (node->m_data_type==DATATYPE_SET) {
			List<FeatureTerm> l_features;

			l_features.Instance(*(node->m_value.m_set));
			l_features.Rewind();
			while(l_features.Iterate(ft)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) {

					path2=new Path;
					path2->Copy(*path);

					open_paths.Add(path2);
					open_nodes.Add(ft->m_ft);
					open_sorts.Add(sort);
				} /* if */ 

				/* add another path to the node: */ 
				pos=resultn->PositionRef(ft);
				if (pos==-1) {
					path2=new Path;
					path2->Copy(*path);
					resultn->Add(ft);
					pathl=new List<Path>;
					pathl->Add(path2);
					resultp->Add(pathl);
					sortl=new List<Sort>;
					sortl->Add(sort);
					results->Add(sortl);
				} else {
					path2=new Path;
					path2->Copy(*path);
					pathl=resultp->operator [](pos);
					pathl->Add(path2);
					sortl=results->operator [](pos);
					sortl->Add(sort);
				} /* if */ 	
			} /* while */ 
		} /* if */ 
	} /* while */ 
	
	while(!nodes.EmptyP()) nodes.ExtractIni();
	while(!sorts.EmptyP()) sorts.ExtractIni();

	if (nl!=0) {
		*nl=resultn;
	} else {
		delete resultn;
	} /* if */ 
	if (pl!=0) {
		*pl=resultp;
	} else {
		delete resultp;
	} /* if */ 
	if (sl!=0) {
		*sl=results;
	} else {
		delete results;
	} /* if */ 
} /* FeatureTerm::nodesAllPathsSorts */ 


void FeatureTerm::nodesAllPathsSortsParents(List<FeatureTerm> **nl,List< List<Path> > **pl,List< List<Sort> > **sl,List< List<FeatureTerm> > **parentsl,Ontology *o)
{
	int pos;
	List<FeatureTerm> *resultn=new List<FeatureTerm>;
	List< List<Path> > *resultp=new List< List<Path> >;
	List<Path> *pathl;
	List< List<Sort> > *results=new List< List<Sort> >;
	List<Sort> *sortl;
	List< List<FeatureTerm> > *resultparents=new List< List<FeatureTerm> >;
	List<FeatureTerm> *parentl;
	FeatureTerm *ft;
	List<FeatureTermContainer> open_nodes,nodes;
	List<Path> open_paths,paths;
	List<Sort> open_sorts,sorts;
	Path *path,*path2;
	FeatureTermContainer *node;
	Sort *sort;

	resultn->Add(this);
	pathl=new List<Path>;
	pathl->Add(new Path);
	resultp->Add(pathl);
	sortl=new List<Sort>;
	sortl->Add(o->get_sort("any"));
	results->Add(sortl);
	parentl=new List<FeatureTerm>;
	parentl->Add(0);
	resultparents->Add(parentl);

	open_nodes.Add(m_ft);
	open_paths.Add(new Path);
	open_sorts.Add(o->get_sort("any"));

	while(!open_nodes.EmptyP()) {
		node=open_nodes.ExtractIni();
		path=open_paths.ExtractIni();
		sort=open_sorts.ExtractIni();
		
		nodes.Insert(node);
		paths.Insert(path);
		sorts.Insert(sort);

		if (node->m_data_type==DATATYPE_FEATURETERM) {
			List<FeatureTerm> l_features;
			List<Symbol> l_fnames;
			Symbol *fname;

			l_features.Instance(*(node->m_value.m_ft.m_feature_value));
			l_fnames.Instance(*(node->m_value.m_ft.m_feature_name));
			l_features.Rewind();
			l_fnames.Rewind();
			while(l_features.Iterate(ft) &&
				  l_fnames.Iterate(fname)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) {

					path2=new Path;
					path2->Copy(*path);
					path2->Add(new Symbol(fname));

					open_paths.Add(path2);
					open_nodes.Add(ft->m_ft);
					open_sorts.Add(node->m_sort->featureSort(fname));
				} /* if */ 

				/* add another path to the node: */ 
				pos=resultn->PositionRef(ft);
				if (pos==-1) {
					path2=new Path;
					path2->Copy(*path);
					path2->Add(new Symbol(fname));
					resultn->Add(ft);
					pathl=new List<Path>;
					pathl->Add(path2);
					resultp->Add(pathl);
					sortl=new List<Sort>;
					sortl->Add(node->m_sort->featureSort(fname));
					results->Add(sortl);
					parentl=new List<FeatureTerm>;
					parentl->Add(new FeatureTerm(node));
					resultparents->Add(parentl);
				} else {
					path2=new Path;
					path2->Copy(*path);
					path2->Add(new Symbol(fname));
					pathl=resultp->operator [](pos);
					pathl->Add(path2);
					sortl=results->operator [](pos);
					sortl->Add(node->m_sort->featureSort(fname));
					parentl=resultparents->operator [](pos);
					parentl->Add(new FeatureTerm(node));
				} /* if */ 		
			} /* while */ 
		} /* if */ 

		if (node->m_data_type==DATATYPE_SET) {
			List<FeatureTerm> l_features;

			l_features.Instance(*(node->m_value.m_set));
			l_features.Rewind();
			while(l_features.Iterate(ft)) {
				if (!nodes.MemberRefP(ft->m_ft) &&
					!open_nodes.MemberRefP(ft->m_ft)) {

					path2=new Path;
					path2->Copy(*path);

					open_paths.Add(path2);
					open_nodes.Add(ft->m_ft);
					open_sorts.Add(sort);
				} /* if */ 

				/* add another path to the node: */ 
				pos=resultn->PositionRef(ft);
				if (pos==-1) {
					path2=new Path;
					path2->Copy(*path);
					resultn->Add(ft);
					pathl=new List<Path>;
					pathl->Add(path2);
					resultp->Add(pathl);
					sortl=new List<Sort>;
					sortl->Add(sort);
					results->Add(sortl);
					parentl=new List<FeatureTerm>;
					parentl->Add(new FeatureTerm(node));
					resultparents->Add(parentl);
				} else {
					path2=new Path;
					path2->Copy(*path);
					pathl=resultp->operator [](pos);
					pathl->Add(path2);
					sortl=results->operator [](pos);
					sortl->Add(sort);
					parentl=resultparents->operator [](pos);
					parentl->Add(new FeatureTerm(node));
				} /* if */ 	
			} /* while */ 
		} /* if */ 
	} /* while */ 
	
	while(!nodes.EmptyP()) nodes.ExtractIni();
	while(!sorts.EmptyP()) sorts.ExtractIni();

	if (nl!=0) {
		*nl=resultn;
	} else {
		delete resultn;
	} /* if */ 
	if (pl!=0) {
		*pl=resultp;
	} else {
		delete resultp;
	} /* if */ 
	if (sl!=0) {
		*sl=results;
	} else {
		delete results;
	} /* if */ 
	if (parentsl!=0) {
		*parentsl=resultparents;
	} else {
		delete resultparents;
	} /* if */ 
} /* FeatureTerm::nodesAllPathsSortsParents */ 


void FeatureTerm::nodesAllPathsSortsParents(List<FeatureTerm> **nl,List< List<Path> > **pl,List< List<Sort> > **sl,List< List<FeatureTerm> > **parentsl,Ontology *o,FTKBase *domain_model)
{
	int pos;
	List<FeatureTerm> *resultn=new List<FeatureTerm>;
	List< List<Path> > *resultp=new List< List<Path> >;
	List<Path> *pathl;
	List< List<Sort> > *results=new List< List<Sort> >;
	List<Sort> *sortl;
	List< List<FeatureTerm> > *resultparents=new List< List<FeatureTerm> >;
	List<FeatureTerm> *parentl;
	FeatureTerm *ft;
	List<FeatureTermContainer> open_nodes,nodes;
	List<Path> open_paths,paths;
	List<Sort> open_sorts,sorts;
	Path *path,*path2;
	FeatureTermContainer *node;
	Sort *sort;

	resultn->Add(this);
	pathl=new List<Path>;
	pathl->Add(new Path);
	resultp->Add(pathl);
	sortl=new List<Sort>;
	sortl->Add(o->get_sort("any"));
	results->Add(sortl);
	parentl=new List<FeatureTerm>;
	parentl->Add(0);
	resultparents->Add(parentl);

	open_nodes.Add(m_ft);
	open_paths.Add(new Path);
	open_sorts.Add(o->get_sort("any"));

	while(!open_nodes.EmptyP()) {
		node=open_nodes.ExtractIni();
		path=open_paths.ExtractIni();
		sort=open_sorts.ExtractIni();
		
		nodes.Insert(node);
		paths.Insert(path);
		sorts.Insert(sort);

		if (domain_model==0 || !domain_model->MemberP(node)) {

			if (node->m_data_type==DATATYPE_FEATURETERM) {
				List<FeatureTerm> l_features;
				List<Symbol> l_fnames;
				Symbol *fname;

				l_features.Instance(*(node->m_value.m_ft.m_feature_value));
				l_fnames.Instance(*(node->m_value.m_ft.m_feature_name));
				l_features.Rewind();
				l_fnames.Rewind();
				while(l_features.Iterate(ft) &&
					  l_fnames.Iterate(fname)) {
					if (!nodes.MemberRefP(ft->m_ft) &&
						!open_nodes.MemberRefP(ft->m_ft)) {

						path2=new Path;
						path2->Copy(*path);
						path2->Add(new Symbol(fname));

						open_paths.Add(path2);
						open_nodes.Add(ft->m_ft);
						open_sorts.Add(node->m_sort->featureSort(fname));
					} /* if */ 

					/* add another path to the node: */ 
					pos=resultn->PositionRef(ft);
					if (pos==-1) {
						path2=new Path;
						path2->Copy(*path);
						path2->Add(new Symbol(fname));
						resultn->Add(ft);
						pathl=new List<Path>;
						pathl->Add(path2);
						resultp->Add(pathl);
						sortl=new List<Sort>;
						sortl->Add(node->m_sort->featureSort(fname));
						results->Add(sortl);
						parentl=new List<FeatureTerm>;
						parentl->Add(new FeatureTerm(node));
						resultparents->Add(parentl);
					} else {
						path2=new Path;
						path2->Copy(*path);
						path2->Add(new Symbol(fname));
						pathl=resultp->operator [](pos);
						pathl->Add(path2);
						sortl=results->operator [](pos);
						sortl->Add(node->m_sort->featureSort(fname));
						parentl=resultparents->operator [](pos);
						parentl->Add(new FeatureTerm(node));
					} /* if */ 		
				} /* while */ 
			} /* if */ 

			if (node->m_data_type==DATATYPE_SET) {
				List<FeatureTerm> l_features;

				l_features.Instance(*(node->m_value.m_set));
				l_features.Rewind();
				while(l_features.Iterate(ft)) {
					if (!nodes.MemberRefP(ft->m_ft) &&
						!open_nodes.MemberRefP(ft->m_ft)) {

						path2=new Path;
						path2->Copy(*path);

						open_paths.Add(path2);
						open_nodes.Add(ft->m_ft);
						open_sorts.Add(sort);
					} /* if */ 

					/* add another path to the node: */ 
					pos=resultn->PositionRef(ft);
					if (pos==-1) {
						path2=new Path;
						path2->Copy(*path);
						resultn->Add(ft);
						pathl=new List<Path>;
						pathl->Add(path2);
						resultp->Add(pathl);
						sortl=new List<Sort>;
						sortl->Add(sort);
						results->Add(sortl);
						parentl=new List<FeatureTerm>;
						parentl->Add(new FeatureTerm(node));
						resultparents->Add(parentl);
					} else {
						path2=new Path;
						path2->Copy(*path);
						pathl=resultp->operator [](pos);
						pathl->Add(path2);
						sortl=results->operator [](pos);
						sortl->Add(sort);
						parentl=resultparents->operator [](pos);
						parentl->Add(new FeatureTerm(node));
					} /* if */ 	
				} /* while */ 
			} /* if */ 
		} /* if */ 
	} /* while */ 
	
	while(!nodes.EmptyP()) nodes.ExtractIni();
	while(!sorts.EmptyP()) sorts.ExtractIni();

	if (nl!=0) {
		*nl=resultn;
	} else {
		delete resultn;
	} /* if */ 
	if (pl!=0) {
		*pl=resultp;
	} else {
		delete resultp;
	} /* if */ 
	if (sl!=0) {
		*sl=results;
	} else {
		delete results;
	} /* if */ 
	if (parentsl!=0) {
		*parentsl=resultparents;
	} else {
		delete resultparents;
	} /* if */ 
} /* FeatureTerm::nodesAllPathsSortsParents */ 


void FeatureTerm::Allnodes(List<FeatureTerm> **nl,Ontology *o,FTKBase *domain_model)
{
	int pos;
	List<FeatureTerm> *resultn=new List<FeatureTerm>;
	FeatureTerm *ft;
	List<FeatureTermContainer> open_nodes,nodes;
	List<Path> open_paths,paths;
	FeatureTermContainer *node;

	resultn->Add(this);

	open_nodes.Add(m_ft);

	while(!open_nodes.EmptyP()) {
		node=open_nodes.ExtractIni();
		
		nodes.Insert(node);

		if (domain_model==0 || !domain_model->MemberP(node)) {

			if (node->m_data_type==DATATYPE_FEATURETERM) {
				List<FeatureTerm> l_features;
				List<Symbol> l_fnames;
				Symbol *fname;

				l_features.Instance(*(node->m_value.m_ft.m_feature_value));
				l_fnames.Instance(*(node->m_value.m_ft.m_feature_name));
				l_features.Rewind();
				l_fnames.Rewind();
				while(l_features.Iterate(ft) &&
					  l_fnames.Iterate(fname)) {
					if (!nodes.MemberRefP(ft->m_ft) &&
						!open_nodes.MemberRefP(ft->m_ft)) {

						open_nodes.Add(ft->m_ft);
					} /* if */ 

					/* add another path to the node: */ 
					pos=resultn->PositionRef(ft);
					if (pos==-1) {
						resultn->Add(ft);
					} /* if */ 		
				} /* while */ 
			} /* if */ 

			if (node->m_data_type==DATATYPE_SET) {
				List<FeatureTerm> l_features;

				l_features.Instance(*(node->m_value.m_set));
				l_features.Rewind();
				while(l_features.Iterate(ft)) {
					if (!nodes.MemberRefP(ft->m_ft) &&
						!open_nodes.MemberRefP(ft->m_ft)) {

						open_nodes.Add(ft->m_ft);
					} /* if */ 

					/* add another path to the node: */ 
					pos=resultn->PositionRef(ft);
					if (pos==-1) {
						resultn->Add(ft);
					} /* if */ 	
				} /* while */ 
			} /* if */ 
		} /* if */ 
	} /* while */ 
	
	while(!nodes.EmptyP()) nodes.ExtractIni();

	if (nl!=0) {
		*nl=resultn;
	} else {
		delete resultn;
	} /* if */ 
} /* FeatureTerm::AllnodesAllPathsSorts */ 



List<FeatureTerm> *FeatureTerm::set_values(void)
{
	if (m_ft==0) return 0;
	if (m_ft->m_data_type==DATATYPE_SET) {
		List<FeatureTerm> *result=new List<FeatureTerm>;
		List<FeatureTerm> l;
		FeatureTerm *ft;

		l.Instance(*(m_ft->m_value.m_set));
		l.Rewind();
		while(l.Iterate(ft)) result->Add(new FeatureTerm(ft));

		return result;
	} else {
		return 0;
	} /* if */  

} /* FeatureTerm::set_values */ 


List<FeatureTerm> *FeatureTerm::set_values_quick(void)
{
	if (m_ft==0) return 0;
	if (m_ft->m_data_type==DATATYPE_SET) {
		return m_ft->m_value.m_set;
	} else {
		return 0;
	} /* if */  

} /* FeatureTerm::set_values_quick */ 



int FeatureTerm::substitute(FeatureTerm *v1,FeatureTerm *v2)
{
//	List<FeatureTerm> *l=new List<FeatureTerm>;
	FeatureTerm *ft;
	List<FeatureTerm> open_nodes,nodes;
	FeatureTerm *node;
	int substitutions=0;

	List<FeatureTerm> substitution_l;

//	printf("/--- SUBSTITUTING ---\\\n");
	open_nodes.Add(this);

	while(!open_nodes.EmptyP()) {
		node=open_nodes.ExtractIni();
		nodes.Add(node);

//		printf("NODE: %s\n",node->getSort()->get());
		if (node->m_ft==v1->m_ft) substitution_l.Add(node);

		if (node->m_ft->m_data_type==DATATYPE_FEATURETERM) {
			List<FeatureTerm> l_features;

			l_features.Instance(*(node->m_ft->m_value.m_ft.m_feature_value));
			l_features.Rewind();
			while(l_features.Iterate(ft)) {
//				printf("feature: %s\n",(node->m_ft->m_value.m_ft.m_feature_name)->operator []((node->m_ft->m_value.m_ft.m_feature_value)->PositionRef(ft))->get());
				if (!nodes.MemberRefP(ft) &&
					!open_nodes.MemberRefP(ft)) open_nodes.Add(ft);
			} /* while */ 
		} /* if */ 

		if (node->m_ft->m_data_type==DATATYPE_SET) {
			List<FeatureTerm> l_features;

			l_features.Instance(*(node->m_ft->m_value.m_set));
			l_features.Rewind();
			while(l_features.Iterate(ft)) {
				if (!nodes.MemberRefP(ft) &&
					!open_nodes.MemberRefP(ft)) open_nodes.Add(ft);
			} /* while */ 
		} /* if */ 
	} /* while */ 

	while(!substitution_l.EmptyP()) {
		node=substitution_l.ExtractIni();
		if (v2->m_ft!=0) v2->m_ft->m_reference_count++;
		node->Delete();
		node->m_ft=v2->m_ft;
		substitutions++;
	} /* while */ 

//	printf("\\--- SUBSTITUTING ---/\n");
	
	while(!nodes.EmptyP()) nodes.ExtractIni();
	return substitutions;
} /* FeatureTerm::substitute */ 




FeatureTerm *FeatureTerm::clone_substituting(FeatureTerm *v1,FeatureTerm *v2)
{
	FeatureTerm *f;
	List<FeatureTermContainer> old_c;
	List<FeatureTerm> new_c;

	old_c.Add(v1->m_ft);
	new_c.Add(v2);

	f=cloneInternal(&old_c,&new_c);

	while(!old_c.EmptyP()) old_c.ExtractIni();
	while(!new_c.EmptyP()) new_c.ExtractIni();

	return f;
} /* FeatureTerm::clone_substituting */ 



FeatureTerm *FeatureTerm::clone_substituting(FeatureTerm *v1,FeatureTerm *v2,FTKBase *dm)
{
	FeatureTerm *f;
	List<FeatureTermContainer> old_c;
	List<FeatureTerm> new_c;

	old_c.Add(v1->m_ft);
	new_c.Add(v2);

	if (dm!=0) f=cloneInternal(&old_c,&new_c,dm);
		  else f=cloneInternal(&old_c,&new_c);

	while(!old_c.EmptyP()) old_c.ExtractIni();
	while(!new_c.EmptyP()) new_c.ExtractIni();

	return f;
} /* FeatureTerm::clone_substituting */ 




FeatureTerm *FeatureTerm::clone_linking(FeatureTerm *p_v1,FeatureTerm *p_v2,FTKBase *dm) 
{
	FeatureTerm *f,*ft,*tmp_v1,*tmp_v2;
	List<FeatureTermContainer> old_c;
	List<FeatureTerm> new_c;
	FeatureTermContainer *ftv;
	FeatureTermContainer *new_v1,*new_v2;
	FeatureTermContainer *v1=p_v1->m_ft,*v2=p_v2->m_ft;

	if (dm!=0) f=cloneInternal(&old_c,&new_c,dm);
		  else f=cloneInternal(&old_c,&new_c);

	old_c.Rewind();
	new_c.Rewind();
	new_v1=0;
	while(new_v1==0 && old_c.Iterate(ftv) && new_c.Iterate(ft)) {
		if (ftv==v1) new_v1=ft->m_ft;
	} /* while */ 

	old_c.Rewind();
	new_c.Rewind();
	new_v2=0;
	while(new_v2==0 && old_c.Iterate(ftv) && new_c.Iterate(ft)) {
		if (ftv==v2) new_v2=ft->m_ft;
	} /* while */ 

	if (new_v1==0 || new_v2==0) {
		char *s;
		s=this->toStringNOOS(dm);
		printf("Base:\n%s\n",s);
		delete []s;
		s=f->toStringNOOS(dm);
		printf("Clone:\n%s\n",s);
		delete []s;
		printf("Warning: clone_linking!\n");
	} /* if */ 

	/* Add path equalty: */ 
	tmp_v1=new FeatureTerm(new_v1);
	tmp_v2=new FeatureTerm(new_v2);
	new_v1=tmp_v1->m_ft;
	new_v2=tmp_v2->m_ft;

	f->substitute(tmp_v1,tmp_v2);

	// delete the temporal copies of new_v1 and new_v2
	delete tmp_v1;
	delete tmp_v2;

	while(!old_c.EmptyP()) old_c.ExtractIni();
	while(!new_c.EmptyP()) new_c.ExtractIni();

	return f;
} /* FeatureTerm::clone_linking */ 



bool FeatureTerm::hasSetsP(void)
{
	List<FeatureTermContainer> l;
	bool retval=false;

	retval=hasSetsP_internal(&l);

	while(!l.EmptyP()) l.ExtractIni();

	return retval;
} /* FeatureTerm::hasSetsP */ 


bool FeatureTerm::hasSetsP_internal(List<class FeatureTermContainer> *l)
{
	if (l->MemberRefP(m_ft)) return false;
	if (m_ft->m_data_type==DATATYPE_SET) return true;

	l->Add(m_ft);

	if (m_ft->m_data_type==DATATYPE_FEATURETERM) {
		FeatureTerm *ft;
		List<FeatureTerm> l_features;

		l_features.Instance(*(m_ft->m_value.m_ft.m_feature_value));
		l_features.Rewind();
		while(l_features.Iterate(ft)) {
			if (ft->hasSetsP_internal(l)) return true;
		} /* while */ 
	} /* if */ 

	return false;
} /* FeatureTerm::hasSetsP_internal */ 


bool FeatureTerm::hasPathEqualtiesP(void)
{
	List<FeatureTermContainer> l;
	bool retval=false;

	retval=hasPathEqualtiesP_internal(&l);

	while(!l.EmptyP()) l.ExtractIni();

	return retval;
} /* FeatureTerm::hasPathEqualtiesP */ 


bool FeatureTerm::hasPathEqualtiesP_internal(List<class FeatureTermContainer> *l)
{
	if (l->MemberRefP(m_ft)) return true;

	l->Add(m_ft);

	if (m_ft->m_data_type==DATATYPE_FEATURETERM) {
		FeatureTerm *ft;
		List<FeatureTerm> l_features;

		l_features.Instance(*(m_ft->m_value.m_ft.m_feature_value));
		l_features.Rewind();
		while(l_features.Iterate(ft)) {
			if (ft->hasPathEqualtiesP_internal(l)) return true;
		} /* while */ 
	} /* if */ 

	if (m_ft->m_data_type==DATATYPE_SET) {
		FeatureTerm *ft;
		List<FeatureTerm> l_features;

		l_features.Instance(*(m_ft->m_value.m_set));
		l_features.Rewind();
		while(l_features.Iterate(ft)) {
			if (ft->hasPathEqualtiesP_internal(l)) return true;
		} /* while */ 
	} /* if */ 

	return false;
} /* FeatureTerm::hasPathEqualtiesP_internal */ 


bool FeatureTerm::hasPathEqualtiesP(FTKBase *dm)
{
	List<FeatureTermContainer> l;
	bool retval=false;

	retval=hasPathEqualtiesP_internal(&l,dm);

	while(!l.EmptyP()) l.ExtractIni();

	return retval;
} /* FeatureTerm::hasPathEqualtiesP */ 


bool FeatureTerm::hasPathEqualtiesP_internal(List<class FeatureTermContainer> *l,FTKBase *dm)
{
	if (dm->MemberP(this)) return false;
	if (l->MemberRefP(m_ft)) return true;

	l->Add(m_ft);

	if (m_ft->m_data_type==DATATYPE_FEATURETERM) {
		FeatureTerm *ft;
		List<FeatureTerm> l_features;

		l_features.Instance(*(m_ft->m_value.m_ft.m_feature_value));
		l_features.Rewind();
		while(l_features.Iterate(ft)) {
			if (ft->hasPathEqualtiesP_internal(l,dm)) return true;
		} /* while */ 
	} /* if */ 

	if (m_ft->m_data_type==DATATYPE_SET) {
		FeatureTerm *ft;
		List<FeatureTerm> l_features;

		l_features.Instance(*(m_ft->m_value.m_set));
		l_features.Rewind();
		while(l_features.Iterate(ft)) {
			if (ft->hasPathEqualtiesP_internal(l,dm)) return true;
		} /* while */ 
	} /* if */ 

	return false;
} /* FeatureTerm::hasPathEqualtiesP_internal */ 


void FeatureTerm::set_paths(List<Path> *l)
{
	FeatureTerm *ft;
	List<FeatureTermContainer> open_nodes,nodes;
	List<Path> open_paths,paths;
	FeatureTermContainer *node;
	Path *path,*path2;
	Symbol *path_feature;
	List<FeatureTerm> l_features;
	List<Symbol> l_fnames;
	Symbol *fname;

	open_nodes.Add(m_ft);
	open_paths.Add(new Path);

	while(!open_nodes.EmptyP()) {
		node=open_nodes.ExtractIni();
		path=open_paths.ExtractIni();

		nodes.Add(node);
		paths.Add(path);

		if (node->m_data_type==DATATYPE_FEATURETERM) {
			l_features.Instance(*(node->m_value.m_ft.m_feature_value));
			l_fnames.Instance(*(node->m_value.m_ft.m_feature_name));
			l_features.Rewind();
			l_fnames.Rewind();
			while(l_features.Iterate(ft) &&
				  l_fnames.Iterate(fname)) {
				if (!nodes.MemberRefP(ft->m_ft)) {
					if (!open_nodes.MemberRefP(ft->m_ft)) {

						path2=new Path;
						path->Rewind();
						while(path->Iterate(path_feature)) path2->Add(path_feature);
						path2->Add(fname);
						
						open_nodes.Add(ft->m_ft);
						open_paths.Add(path2);
					} /* if */ 
				} /* if */ 
			} /* while */ 
		} /* if */ 

		if (node->m_data_type==DATATYPE_SET) {		
			/* Add the current path to l: */ 
			if (!l->MemberP(path)) {
				path2=new Path;
				path->Rewind();
				while(path->Iterate(path_feature)) path2->Add(new Symbol(path_feature));
				l->Add(path2);
			} /* if */ 

			l_features.Instance(*(node->m_value.m_set));
			l_features.Rewind();
			while(l_features.Iterate(ft)) {
				if (!nodes.MemberRefP(ft->m_ft)) {
					if (!open_nodes.MemberRefP(ft->m_ft)) {
					
						path2=new Path;
						path->Rewind();
						while(path->Iterate(path_feature)) path2->Add(path_feature);

						open_nodes.Add(ft->m_ft);
						open_paths.Add(path2);
					} /* if */ 
				} /* if */ 
			} /* while */ 


		} /* if */ 

	} /* while */ 

	while(!nodes.EmptyP()) nodes.ExtractIni();
	while(!paths.EmptyP()) {
		path=paths.ExtractIni();
		while(!path->EmptyP()) path->ExtractIni();
		delete path;
	} /* while */ 

	/* show results: */ 
/*
	{
		char *s;

		s=toNiceString();
		printf("Sets for: %s\n",s);
		delete s;
		l->Rewind();
		while(l->Iterate(path)) {
			printf("*---- Set Path ----*\n");
			path->Rewind();
			while(path->Iterate(path_feature)) printf("%s ",path_feature->get());
			printf("\n");
		} // while 
	}
*/

} /* FeatureTerm::set_paths */ 


void FeatureTerm::set_paths_intersection(List<Path> *l)
{
	FeatureTerm *ft;
	List<FeatureTermContainer> open_nodes,nodes;
	List<Path> open_paths,paths;
	FeatureTermContainer *node;
	Path *path,*path2;
	Symbol *path_feature;
	List<FeatureTerm> l_features;
	List<Symbol> l_fnames;
	Symbol *fname;
	List<Path> previous;

	while(!l->EmptyP()) previous.Add(l->ExtractIni());

	open_nodes.Add(m_ft);
	open_paths.Add(new Path);

	while(!open_nodes.EmptyP()) {
		node=open_nodes.ExtractIni();
		path=open_paths.ExtractIni();

		nodes.Add(node);
		paths.Add(path);

		if (node->m_data_type==DATATYPE_FEATURETERM) {
			l_features.Instance(*(node->m_value.m_ft.m_feature_value));
			l_fnames.Instance(*(node->m_value.m_ft.m_feature_name));
			l_features.Rewind();
			l_fnames.Rewind();
			while(l_features.Iterate(ft) &&
				  l_fnames.Iterate(fname)) {
				if (!nodes.MemberRefP(ft->m_ft)) {
					if (!open_nodes.MemberRefP(ft->m_ft)) {

						path2=new Path;
						path->Rewind();
						while(path->Iterate(path_feature)) path2->Add(path_feature);
						path2->Add(fname);
						
						open_nodes.Add(ft->m_ft);
						open_paths.Add(path2);
					} /* if */ 
				} /* if */ 
			} /* while */ 
		} /* if */ 

		if (node->m_data_type==DATATYPE_SET) {		
			/* Add the current path to l: */ 
			if (!l->MemberP(path) && previous.MemberP(path)) {
				path2=new Path;
				path->Rewind();
				while(path->Iterate(path_feature)) path2->Add(new Symbol(path_feature));
				l->Add(path2);
			} /* if */ 

			l_features.Instance(*(node->m_value.m_set));
			l_features.Rewind();
			while(l_features.Iterate(ft)) {
				if (!nodes.MemberRefP(ft->m_ft)) {
					if (!open_nodes.MemberRefP(ft->m_ft)) {
					
						path2=new Path;
						path->Rewind();
						while(path->Iterate(path_feature)) path2->Add(path_feature);

						open_nodes.Add(ft->m_ft);
						open_paths.Add(path2);
					} /* if */ 
				} /* if */ 
			} /* while */ 


		} /* if */ 

	} /* while */ 

	while(!nodes.EmptyP()) nodes.ExtractIni();
	while(!paths.EmptyP()) {
		path=paths.ExtractIni();
		while(!path->EmptyP()) path->ExtractIni();
		delete path;
	} /* while */ 

	/* show results: */ 
/*
	{
		char *s;

		s=toNiceString();
		printf("Sets for: %s\n",s);
		delete s;
		l->Rewind();
		while(l->Iterate(path)) {
			printf("*---- Set Path ----*\n");
			path->Rewind();
			while(path->Iterate(path_feature)) printf("%s ",path_feature->get());
			printf("\n");
		} // while 
	}
*/
} /* FeatureTerm::set_paths_intersection */ 



bool FeatureTerm::leafP(void)
{
	return (isInt() || isFloat() || isSymbol() || isAbstract() || (isFeatureTerm() && m_ft->m_value.m_ft.m_feature_value->EmptyP()));
} /* FeatureTerm::leafP */ 



// Makes an independent copy of a list of Feature Terms (maintaining their relations)
List<FeatureTerm> *FeatureTerm::clone(List<FeatureTerm> *l)
{
	FeatureTerm *f,*f2;
	List<FeatureTermContainer> old_c;
	List<FeatureTerm> new_c;

	List<FeatureTerm> *l2=new List<FeatureTerm>;

	l->Rewind();
	while(l->Iterate(f)) {
		if (f!=0) {
			f2=f->cloneInternal(&old_c,&new_c);
			l2->Add(f2);
		} else {
			l2->Add(0);
		} // if 
	} /* while */ 

	while(!old_c.EmptyP()) old_c.ExtractIni();
	while(!new_c.EmptyP()) new_c.ExtractIni();

	return l2;
} /* FeatureTerm::clone */ 


// Makes an independent copy of a list of Feature Terms (maintaining their relations)
List<FeatureTerm> *FeatureTerm::clone(List<FeatureTerm> *l,FTKBase *dm)
{
	FeatureTerm *f,*f2;
	List<FeatureTermContainer> old_c;
	List<FeatureTerm> new_c;

	List<FeatureTerm> *l2=new List<FeatureTerm>;

	l->Rewind();
	while(l->Iterate(f)) {
		if (f!=0) {
			if (dm!=0) f2=f->cloneInternal(&old_c,&new_c,dm);
				  else f2=f->cloneInternal(&old_c,&new_c);
			l2->Add(f2);
		} else {
			l2->Add(0);
		} // if 
	} /* while */ 

	while(!old_c.EmptyP()) old_c.ExtractIni();
	while(!new_c.EmptyP()) new_c.ExtractIni();

	return l2;
} /* FeatureTerm::clone */ 


int FeatureTerm::num_of_references(void)
{
	if (m_ft==0) return 0;
	return m_ft->m_reference_count;
} /* FeatureTerm::num_of_references */ 

